This commit is contained in:
xsl
2026-03-12 21:13:07 +08:00
parent f7982d45de
commit 55c64a6db4
149 changed files with 15472 additions and 1 deletions
@@ -0,0 +1,21 @@
import { CameraView } from "./camera";
export class CameraManager {
private cameraView: CameraView | null = null;
private static instance: CameraManager | null = null;
public static getInstance(): CameraManager {
if (CameraManager.instance == null) {
CameraManager.instance = new CameraManager();
}
return CameraManager.instance!;
}
public setCameraView(cameraView?: CameraView): void {
this.cameraView = cameraView!;
}
public getCameraView(): CameraView | null {
return this.cameraView;
}
public dispose(): void {
this.cameraView = null;
}
}
//# sourceMappingURL=CameraManager.uts.map
@@ -0,0 +1 @@
{"version":3,"file":"CameraManager.uts","sourceRoot":"","sources":["uni_modules/Skin-cameraUTS/utssdk/app-android/CameraManager.uts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,MAAM,OAAO,aAAa;IACzB,OAAO,CAAC,UAAU,EAAG,UAAU,GAAG,IAAI,GAAG,IAAI,CAAC;IAE9C,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAG,aAAa,GAAG,IAAI,GAAG,IAAI,CAAC;IAEtD,MAAM,CAAC,MAAM,CAAC,WAAW,IAAK,aAAa;QAC1C,IAAI,aAAa,CAAC,QAAQ,IAAI,IAAI,EAAE;YACnC,aAAa,CAAC,QAAQ,GAAG,IAAI,aAAa,EAAE,CAAC;SAC7C;QACD,OAAO,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,CAAC,aAAa,CAAC,UAAW,CAAC,EAAE,UAAU,GAAI,IAAI;QACpD,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC,CAAA;IAC9B,CAAC;IAED,MAAM,CAAC,aAAa,IAAK,UAAU,GAAG,IAAI;QACzC,OAAO,IAAI,CAAC,UAAU,CAAC;IACxB,CAAC;IAED,MAAM,CAAC,OAAO,IAAK,IAAI;QACtB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;IACxB,CAAC;CACD","sourcesContent":["import { CameraView } from \"./camera\";\r\n\r\nexport class CameraManager {\r\n\tprivate cameraView : CameraView | null = null;\r\n\r\n\tprivate static instance : CameraManager | null = null;\r\n\r\n\tpublic static getInstance() : CameraManager {\r\n\t\tif (CameraManager.instance == null) {\r\n\t\t\tCameraManager.instance = new CameraManager();\r\n\t\t}\r\n\t\treturn CameraManager.instance!;\r\n\t}\r\n\r\n\tpublic setCameraView(cameraView ?: CameraView) : void {\r\n\t\tthis.cameraView = cameraView!\r\n\t}\r\n\r\n\tpublic getCameraView() : CameraView | null {\r\n\t\treturn this.cameraView;\r\n\t}\r\n\r\n\tpublic dispose() : void {\r\n\t\tthis.cameraView = null;\r\n\t}\r\n}"]}
@@ -0,0 +1,415 @@
import ProcessCameraProvider from 'androidx.camera.lifecycle.ProcessCameraProvider';
import Preview from 'androidx.camera.core.Preview';
import MirrorMode from 'androidx.camera.core.MirrorMode';
import PreviewView from 'androidx.camera.view.PreviewView';
import Context from 'android.content.Context';
import FrameLayout from 'android.widget.FrameLayout';
import ViewGroup from 'android.view.ViewGroup';
import CameraSelector from 'androidx.camera.core.CameraSelector';
import ImageAnalysis from 'androidx.camera.core.ImageAnalysis';
import UseCaseGroup from 'androidx.camera.core.UseCaseGroup';
import ContextCompat from 'androidx.core.content.ContextCompat';
import LifecycleOwner from 'androidx.lifecycle.LifecycleOwner';
import ImageCapture from 'androidx.camera.core.ImageCapture';
import Size from 'android.util.Size';
import ImageCaptureException from 'androidx.camera.core.ImageCaptureException';
import File from 'java.io.File';
import ImageProxy from 'androidx.camera.core.ImageProxy';
import CameraControl from 'androidx.camera.core.CameraControl';
import VideoCapture from 'androidx.camera.video.VideoCapture';
import Recorder from 'androidx.camera.video.Recorder';
import Recording from 'androidx.camera.video.Recording';
import FileOutputOptions from 'androidx.camera.video.FileOutputOptions';
import Quality from 'androidx.camera.video.Quality';
import QualitySelector from 'androidx.camera.video.QualitySelector';
import VideoRecordEvent from 'androidx.camera.video.VideoRecordEvent';
// import Bitmap from 'android.graphics.Bitmap';
// import FileOutputStream from 'java.io.FileOutputStream';
// import MediaMetadataRetriever from 'android.media.MediaMetadataRetriever';
import ExecutorService from 'java.util.concurrent.ExecutorService';
import Executors from 'java.util.concurrent.Executors';
import ImageFormat from 'android.graphics.ImageFormat';
import { TakePhotoOption, GeneralCallbackResult, TakePhotoSuccessCallbackResult, CameraContextSetZoomOption, SetZoomSuccessCallbackResult, CameraContextStopRecordOption, CameraContextStartRecordOption, StartRecordTimeoutCallbackResult, StopRecordSuccessCallbackResult, OnCameraFrameCallback, OnCameraFrameCallbackResult, CameraFrameListenerStartOption, StopOption, CameraConfig, FlashMode, DevicePosition, Resolution,
//FrameSize,
QualityType, OnCameraFrameListenerOption } from '../interface';
import Bitmap from "android.graphics.Bitmap";
import FileOutputStream from "java.io.FileOutputStream";
const FLASH_MODE_MAP = new Map<string, Int>([
['auto', ImageCapture.FLASH_MODE_AUTO],
['on', ImageCapture.FLASH_MODE_ON],
['torch', ImageCapture.FLASH_MODE_ON],
['off', ImageCapture.FLASH_MODE_OFF],
]);
const DEVICE_POSITION_MAP = new Map<string, Int>([
['back', CameraSelector.LENS_FACING_BACK],
['front', CameraSelector.LENS_FACING_FRONT],
]);
const RESOLUTION_MAP = new Map<string, Quality>([
['low', Quality.LOWEST],
['medium', Quality.HD],
['high', Quality.HIGHEST],
]);
const QUALITY_MAP = new Map<string, Int>([
["high", ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY],
["low", ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY],
]);
const MIRROR_MODE = new Map<boolean, Int>([
[true, MirrorMode.MIRROR_MODE_ON],
[false, MirrorMode.MIRROR_MODE_OFF],
]);
export class CameraView extends FrameLayout {
private previewView: PreviewView;
public cameraProvider: ProcessCameraProvider | null = null;
public cameraControl: CameraControl | null = null;
private imageCapture: ImageCapture | null = null;
private videoCapture: VideoCapture<Recorder> | null = null;
private recording: Recording | null = null;
private comp: UTSComponent<CameraView>;
private flashMode: FlashMode = 'auto';
private devicePosition: DevicePosition = 'back';
private resolution: Resolution = 'medium';
// private frameSize : FrameSize = 'medium'
private quality: QualityType = 'normal';
private videoFile: File | null = null;
maxZoom: Float = (1).toFloat();
minZoom: Float = (1).toFloat();
private initialized: boolean = false;
private isListening: boolean = false;
private videoSelfieMirror: boolean | null = null;
private cameraContextStopRecordOption: CameraContextStopRecordOption | null = null;
private onCameraFrameCallback: OnCameraFrameCallback | null = null;
private cameraExecutor: ExecutorService | null = null;
private onCameraFrameListenerOption: OnCameraFrameListenerOption | null = null;
constructor(context: Context, comp: UTSComponent<CameraView>, config: CameraConfig = {} as CameraConfig) {
super(context);
this.comp = comp;
this.flashMode = config.flash ?? 'auto';
this.devicePosition = config.devicePosition ?? 'back';
this.resolution = config.resolution ?? 'medium';
// this.frameSize = config.frameSize ?? 'medium'
this.previewView = new PreviewView(context);
let layoutParam = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
this.addView(this.previewView, layoutParam);
this.setupCamera();
}
setupCamera() {
// this.checkSelfPermission().then(() => {
let cameraProviderFuture = ProcessCameraProvider.getInstance(UTSAndroid.getUniActivity()!);
cameraProviderFuture.addListener(() => {
try {
this.cameraProvider = cameraProviderFuture.get();
this.bindCamera();
}
catch (e: any) {
let ret: Map<string, any> = new Map();
ret.set("errMsg", JSON.stringify(e));
this.comp.$emit('error', ret);
}
}, ContextCompat.getMainExecutor(UTSAndroid.getUniActivity()!));
// }).catch((err) => {
// let ret : Map<string, any> = new Map();
// ret.set("errMsg", err ?? '权限不足')
// this.comp.$emit('error', ret)
// })
}
bindCamera() {
let targetResolution = RESOLUTION_MAP.get(this.resolution) ?? Quality.HD;
let captureMode = QUALITY_MAP.get(this.quality) ?? ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY;
// 创建一个Preview对象,用于显示相机预览
let preview = new Preview.Builder()
.build();
preview.setSurfaceProvider(this.previewView.getSurfaceProvider());
// 创建一个ImageCapture对象,用于拍照
let imageCapture = new ImageCapture.Builder()
.setFlashMode(FLASH_MODE_MAP.get(this.flashMode)!)
.setCaptureMode(captureMode)
.build();
// 选择要使用的相机(后置或前置)
let cameraSelector = new CameraSelector.Builder()
.requireLensFacing(DEVICE_POSITION_MAP.get(this.devicePosition)!)
.build();
let recorder = Recorder.Builder()
.setQualitySelector(QualitySelector.from(targetResolution));
let mirrorMode = this.videoSelfieMirror == null ? MirrorMode.MIRROR_MODE_ON_FRONT_ONLY : MIRROR_MODE.get(this.videoSelfieMirror!);
let videoCapture = new VideoCapture.Builder(recorder.build())
.setMirrorMode(mirrorMode!)
.build();
this.videoCapture = videoCapture;
// 将参数应用到 VideoCapture
this.imageCapture = imageCapture;
this.cameraProvider!.unbindAll();
let imageAnalysis = ImageAnalysis.Builder()
// .setTargetResolution(new Size(1280, 720))
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build();
let viewPort = this.previewView.getViewPort()!;
let useCaseGroup = new UseCaseGroup.Builder()
.addUseCase(preview)
.addUseCase(imageAnalysis)
.addUseCase(imageCapture)
.addUseCase(videoCapture)
.setViewPort(viewPort)
.build();
this.cameraExecutor = Executors.newSingleThreadExecutor();
let _this = this;
class Analyzer implements ImageAnalysis.Analyzer {
constructor() {
}
override analyze(image: ImageProxy) {
if (_this.isListening) {
let imageFormat = image.getFormat();
// 获取图像的宽度和高度
let width = image.width;
let height = image.height;
if (imageFormat == ImageFormat.YUV_420_888) {
_this.onCameraFrameCallback?.({
width,
height,
data: image
} as OnCameraFrameCallbackResult);
_this.onCameraFrameListenerOption?.success?.({
width,
height,
data: image
} as OnCameraFrameCallbackResult);
}
}
image.close();
}
override getDefaultTargetResolution(): Size {
// 返回默认的目标分辨率
return Size(640, 480);
}
}
imageAnalysis.setAnalyzer(this.cameraExecutor!, new Analyzer() as ImageAnalysis.Analyzer);
let camera = this.cameraProvider!.bindToLifecycle(UTSAndroid.getUniActivity()! as LifecycleOwner, cameraSelector, useCaseGroup
// preview,
// imageCapture,
// videoCapture
);
this.cameraControl = camera.getCameraControl();
if (!this.initialized) {
this.initialized = true;
let zoomState = camera.getCameraInfo().getZoomState().getValue();
this.maxZoom = zoomState?.getMaxZoomRatio() ?? (1).toFloat();
this.minZoom = zoomState?.getMinZoomRatio() ?? (1).toFloat();
let maxZoom = this.maxZoom;
let ret: Map<string, any> = new Map();
ret.set("maxZoom", maxZoom);
this.comp.$emit('ready', ret);
}
}
unbindCamera() {
this.cameraProvider?.unbindAll();
this.cameraExecutor?.shutdown();
}
// checkSelfPermission() : Promise<boolean> {
// let permissionNeed = ["android.permission.CAMERA", "android.permission.RECORD_AUDIO", "android.permission.READ_EXTERNAL_STORAGE"]
// return new Promise((resoleve, _) => {
// resoleve(true);
// UTSAndroid.requestSystemPermission(UTSAndroid.getUniActivity()!, permissionNeed, function (allRight : boolean, list : string[]) {
// if (allRight) {
// resoleve(true);
// } else {
// reject(list);
// }
// }, function (_ : boolean, grantedList : string[]) {
// //grantedList
// reject(grantedList);
// })
// })
// }
setConfig(config: CameraConfig = {} as CameraConfig) {
this.flashMode = config.flash ?? 'auto';
this.devicePosition = config.devicePosition ?? 'back';
this.resolution = config.resolution ?? 'medium';
// this.frameSize = config.frameSize ?? 'medium'
}
setFlash(mode: FlashMode) {
this.flashMode = mode;
if (FLASH_MODE_MAP.get(mode) == null || this.imageCapture == null)
return;
this.imageCapture!.setFlashMode(FLASH_MODE_MAP.get(mode)!);
}
switchCamera(position: DevicePosition) {
this.devicePosition = position;
if (DEVICE_POSITION_MAP.get(position) == null || this.cameraProvider == null)
return;
this.unbindCamera();
this.bindCamera();
}
isResolutionSupported(context: Context, cameraSelector: CameraSelector, targetResolution: Size): boolean {
return true;
}
takePhoto(option: TakePhotoOption) {
let quality = option.quality ?? "high";
this.quality = quality;
if (quality == 'low') {
this.unbindCamera();
this.bindCamera();
}
// 设置输出目录
let privateDir = UTSAndroid.getAppCachePath()!;
const tempFile = new File(privateDir);
if (!tempFile.exists()) {
tempFile.mkdirs();
}
// 设置文件名
const photoFile = new File(privateDir, Date.now() + '.png');
// 处理镜像
let metadata = new ImageCapture.Metadata();
metadata.setReversedHorizontal(option.selfieMirror ?? DEVICE_POSITION_MAP.get(this.devicePosition)! == CameraSelector.LENS_FACING_FRONT);
const outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).setMetadata(metadata).build();
class OnImageSavedCallback implements ImageCapture.OnImageSavedCallback {
override onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
option.success?.({
tempImagePath: photoFile.getAbsolutePath(),
quality: quality,
errMsg: 'ok'
} as TakePhotoSuccessCallbackResult);
option.complete?.({
errMsg: 'ok'
} as GeneralCallbackResult);
}
override onError(err: ImageCaptureException) {
const result: GeneralCallbackResult = {
errMsg: err.toString()
};
option.fail?.(result);
option.complete?.(result);
}
override onCaptureStarted() {
}
}
this.imageCapture!.takePicture(outputOptions, ContextCompat.getMainExecutor(UTSAndroid.getUniActivity()!), new OnImageSavedCallback() as ImageCapture.OnImageSavedCallback);
}
setZoom(option: CameraContextSetZoomOption) {
if (this.cameraControl != null) {
try {
this.cameraControl!.setZoomRatio(option.zoom.toFloat());
option.success?.({
zoom: option.zoom,
errMsg: 'ok'
} as SetZoomSuccessCallbackResult);
option.complete?.({
errMsg: 'ok'
} as GeneralCallbackResult);
}
catch (e: any) {
const result: GeneralCallbackResult = {
errMsg: e.toString()
};
option.complete?.(result);
option.fail?.(result);
}
}
else {
const result: GeneralCallbackResult = {
errMsg: '相机不存在'
};
option.complete?.(result);
option.fail?.(result);
}
}
startRecord(option: CameraContextStartRecordOption) {
if (option.selfieMirror != null && this.videoSelfieMirror != option.selfieMirror) {
this.videoSelfieMirror = option.selfieMirror;
this.unbindCamera();
this.bindCamera();
}
if (this.recording != null || this.videoCapture == null) {
option.fail?.({
errMsg: '已经在录制或相机不存在'
} as GeneralCallbackResult);
option.complete?.({
errMsg: '已经在录制或相机不存在'
} as GeneralCallbackResult);
return;
}
// 设置输出目录
let privateDir = UTSAndroid.getAppCachePath()!;
// 设置文件名
this.videoFile = new File(privateDir, Date.now() + 'video.mp4');
let outputFileOptions = new FileOutputOptions.Builder(this.videoFile!).build();
this.recording = this.videoCapture!.output
.prepareRecording(UTSAndroid.getUniActivity()!, outputFileOptions)
.withAudioEnabled()
// .apply(()=>{
// })
.start(ContextCompat.getMainExecutor(UTSAndroid.getUniActivity()!), (recordEvent: VideoRecordEvent) => {
if (recordEvent instanceof VideoRecordEvent.Start) {
option.success?.({
errMsg: 'ok'
} as GeneralCallbackResult);
if (option.timeout != null && option.timeout! > 0) {
setTimeout(() => {
this.recording?.stop();
}, option.timeout!);
}
}
else if (recordEvent instanceof VideoRecordEvent.Finalize) {
this.recording?.close();
this.recording = null;
let tempVideoPath = this.videoFile?.getAbsolutePath()!;
//let tempThumbPath = extractThumbnail(tempVideoPath) ?? ''
this.cameraContextStopRecordOption?.success?.({
tempVideoPath,
errMsg: 'ok'
} as StopRecordSuccessCallbackResult);
option.timeoutCallback?.({
tempVideoPath,
} as StartRecordTimeoutCallbackResult);
}
});
}
stopRecord(option: CameraContextStopRecordOption) {
if (this.recording == null) {
option.fail?.({
errMsg: '未开始录制'
} as GeneralCallbackResult);
option.complete?.({
errMsg: '未开始录制'
} as GeneralCallbackResult);
return;
}
this.cameraContextStopRecordOption = option;
this.recording?.stop();
}
onCameraFrame(callback: OnCameraFrameCallback | null = null) {
this.onCameraFrameCallback = callback;
}
onCameraFrameListener(option: OnCameraFrameListenerOption) {
this.onCameraFrameListenerOption = option;
}
cameraFrameOnStart(option?: CameraFrameListenerStartOption) {
this.isListening = true;
option?.success?.({
errMsg: 'ok'
} as GeneralCallbackResult);
}
cameraFrameOnStop(option?: StopOption) {
this.isListening = false;
option?.success?.({
errMsg: 'ok'
} as GeneralCallbackResult);
}
}
// // 从视频文件中提取封面的函数
// function extractThumbnail(videoUri : string) : string | null {
// let retriever = new MediaMetadataRetriever()
// retriever.setDataSource(videoUri)
// // 提取视频的某一帧作为封面
// let thumbnail = retriever.frameAtTime
// // 保存封面到文件
// if (thumbnail != null) {
// let privateDir = UTSAndroid.getAppCachePath();
// const thumbnailFile = new File(privateDir, Date.now() + '_thumbnail.jpg');
// let outputStream = FileOutputStream(thumbnailFile)
// thumbnail.compress(Bitmap.CompressFormat.JPEG, 90, outputStream)
// outputStream.close()
// return thumbnailFile.getAbsolutePath()
// }
// retriever.release()
// return null
// }
//# sourceMappingURL=camera.uts.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,215 @@
import { CameraView } from './camera';
import { TakePhotoOption, GeneralCallbackResult, CameraContextSetZoomOption, CameraContextStartRecordOption, CameraContextStopRecordOption,
// CameraFrameListener,
OnCameraFrameCallback,
// OnCameraFrameCallbackResult,
CameraFrameListenerStartOption, StopOption, TakePhoto, SetZoom, StartRecord, StopRecord, StartCameraFrame, StopCameraFrame, OnCameraFrameListenerOption, SwitchOption, SwitchCamera } from '../interface';
import { CameraManager } from "./CameraManager";
class CameraFrameListener {
context!: CameraContext;
constructor(context: CameraContext) {
this.context = context;
}
start(): void;
start(option?: CameraFrameListenerStartOption) {
this.context.getCamera().then((camera: CameraView) => {
camera.cameraFrameOnStart(option);
});
}
stop(): void;
stop(option?: StopOption) {
this.context.getCamera().then((camera: CameraView) => {
camera.cameraFrameOnStop(option);
});
}
}
class CameraContext {
private mCameraFrameListener: CameraFrameListener | null = null;
constructor() {
}
getCamera(): Promise<CameraView> {
let cameraPreview = CameraManager.getInstance().getCameraView();
if (cameraPreview != null) {
return Promise.resolve<CameraView>(cameraPreview);
}
let resolveFunc: ((res: CameraView) => void) | null = null;
let rejectFunc: ((res: string) => void) | null = null;
let maxAttempts: number = 5;
let currentAttempt: number = 0;
function attemptGetCamera() {
let camera = CameraManager.getInstance().getCameraView();
if (camera != null) {
resolveFunc?.(camera);
}
else if (currentAttempt < maxAttempts) {
currentAttempt++;
setTimeout(() => {
attemptGetCamera();
}, 100);
}
else {
rejectFunc?.('Camera not found after multiple attempts');
}
}
return new Promise<CameraView>((resolve, reject) => {
resolveFunc = resolve;
rejectFunc = reject;
attemptGetCamera();
});
}
takePhoto(option: TakePhotoOption) {
this.getCamera().then((camera: CameraView) => {
camera.takePhoto(option);
}).catch(() => {
option.fail?.({
errMsg: '未找到相机'
} as GeneralCallbackResult);
option.complete?.({
errMsg: '未找到相机'
} as GeneralCallbackResult);
});
}
setZoom(option: CameraContextSetZoomOption) {
this.getCamera().then((camera: CameraView) => {
camera.setZoom(option);
}).catch(() => {
option.fail?.({
errMsg: '未找到相机'
} as GeneralCallbackResult);
option.complete?.({
errMsg: '未找到相机'
} as GeneralCallbackResult);
});
}
startRecord(option: CameraContextStartRecordOption) {
this.getCamera().then((camera: CameraView) => {
camera.startRecord(option);
}).catch(() => {
option.fail?.({
errMsg: '未找到相机'
} as GeneralCallbackResult);
option.complete?.({
errMsg: '未找到相机'
} as GeneralCallbackResult);
});
}
stopRecord(option: CameraContextStopRecordOption) {
this.getCamera().then((camera: CameraView) => {
camera.stopRecord(option);
}).catch(() => {
option.fail?.({
errMsg: '未找到相机'
} as GeneralCallbackResult);
option.complete?.({
errMsg: '未找到相机'
} as GeneralCallbackResult);
});
}
onCameraFrame(): CameraFrameListener;
onCameraFrame(callback: OnCameraFrameCallback | null = null): CameraFrameListener {
if (this.mCameraFrameListener == null) {
this.mCameraFrameListener = new CameraFrameListener(this);
}
this.getCamera().then((camera: CameraView) => {
camera.onCameraFrame(callback);
});
return this.mCameraFrameListener!;
}
//////////////////////////////////////////////////////
onCameraFrameListener(option: OnCameraFrameListenerOption) {
this.getCamera().then((camera: CameraView) => {
camera.onCameraFrameListener(option);
}).catch(() => {
__f__('log', 'at uni_modules/Skin-cameraUTS/utssdk/app-android/index.uts:145', "未找到相机");
});
}
cameraFrameOnStart(option: CameraFrameListenerStartOption) {
this.getCamera().then((camera: CameraView) => {
camera.cameraFrameOnStart(option);
}).catch(() => {
option.fail?.({
errMsg: '未找到相机'
} as GeneralCallbackResult);
option.complete?.({
errMsg: '未找到相机'
} as GeneralCallbackResult);
});
}
cameraFrameOnStop(option: StopOption) {
this.getCamera().then((camera: CameraView) => {
camera.cameraFrameOnStop(option);
}).catch(() => {
option.fail?.({
errMsg: '未找到相机'
} as GeneralCallbackResult);
option.complete?.({
errMsg: '未找到相机'
} as GeneralCallbackResult);
});
}
switchCamera(option: SwitchOption) {
this.getCamera().then((camera: CameraView) => {
camera.switchCamera(option.position);
option.success?.({
errMsg: 'ok'
} as GeneralCallbackResult);
option.complete?.({
errMsg: 'ok'
} as GeneralCallbackResult);
}).catch(() => {
option.fail?.({
errMsg: '未找到相机'
} as GeneralCallbackResult);
option.complete?.({
errMsg: '未找到相机'
} as GeneralCallbackResult);
});
}
}
let context: CameraContext = new CameraContext();
export function createCameraContext(): CameraContext {
return context;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
export const takePhoto: TakePhoto = function (options: TakePhotoOption) {
UTSAndroid.getDispatcher("main").async(function (_) {
context.takePhoto(options);
}, null);
};
export const setZoom: SetZoom = function (options: CameraContextSetZoomOption) {
UTSAndroid.getDispatcher("main").async(function (_) {
context.setZoom(options);
}, null);
};
export const startRecord: StartRecord = function (options: CameraContextStartRecordOption) {
UTSAndroid.getDispatcher("main").async(function (_) {
context.startRecord(options);
}, null);
};
export const stopRecord: StopRecord = function (options: CameraContextStopRecordOption) {
UTSAndroid.getDispatcher("main").async(function (_) {
context.stopRecord(options);
}, null);
};
@UTSJS.keepAlive
export function onCameraFrameListener(options: OnCameraFrameListenerOption) {
UTSAndroid.getDispatcher("main").async(function (_) {
context.onCameraFrameListener(options);
}, null);
}
export const startCameraFrame: StartCameraFrame = function (options: CameraFrameListenerStartOption) {
UTSAndroid.getDispatcher("main").async(function (_) {
context.cameraFrameOnStart(options);
}, null);
};
export const stopCameraFrame: StopCameraFrame = function (options: StopOption) {
UTSAndroid.getDispatcher("main").async(function (_) {
context.cameraFrameOnStop(options);
}, null);
};
export const switchCamera: SwitchCamera = function (options: SwitchOption) {
UTSAndroid.getDispatcher("main").async(function (_) {
context.switchCamera(options);
}, null);
};
//# sourceMappingURL=index.uts.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,141 @@
//
//
//
//
//
import { CameraView } from './camera';
import { CameraConfig } from '../interface';
import { CameraManager } from './CameraManager';
//原生提供以下属性或方法的实现
export default {
/**
* 组件名称,也就是开发者使用的标签
*/
name: "xf-camera",
/**
* 组件涉及的事件声明,只有声明过的事件,才能被正常发送
*/
emits: ['stop', 'error', 'ready'],
/**
* 属性声明,组件的使用者会传递这些属性值到组件
*/
props: {
"mode": {
type: String,
default: "normal"
},
"resolution": {
type: String,
default: "medium" // low | high
},
"position": {
type: String,
default: "back" // front前置 |back 后置
},
"flash": {
type: String,
default: "auto" // auto, on, off, torch
},
"frameSize": {
type: String,
default: "medium" // small|large
}
},
/**
* 组件内部变量声明
*/
data(): UTSJSONObject {
return {};
},
/**
* 属性变化监听器实现
*/
watch: {
"position": {
/**
* 这里监听属性变化,并进行组件内部更新
*/
handler(newValue: string, _: string) {
this.$el?.switchCamera(newValue);
},
immediate: false // 创建时是否通过此方法更新属性,默认值为false
},
"flash": {
/**
* 这里监听属性变化,并进行组件内部更新
*/
handler(newValue: string, _: string) {
this.$el?.setFlash(newValue);
},
immediate: false // 创建时是否通过此方法更新属性,默认值为false
}
},
/**
* 规则:如果没有配置expose,则methods中的方法均对外暴露,如果配置了expose,则以expose的配置为准向外暴露
* ['publicMethod'] 含义为:只有 `publicMethod` 在实例上可用
*/
expose: [],
methods: {},
/**
* [可选实现] 组件被创建,组件第一个生命周期,
* 在内存中被占用的时候被调用,开发者可以在这里执行一些需要提前执行的初始化逻辑
*/
created() {
},
/**
* [可选实现] 对应平台的view载体即将被创建,对应前端beforeMount
*/
NVBeforeLoad() {
},
/**
* [必须实现] 创建原生View,必须定义返回值类型
* 开发者需要重点实现这个函数,声明原生组件被创建出来的过程,以及最终生成的原生组件类型
* Android需要明确知道View类型,需特殊校验)
*/
NVLoad(): CameraView {
let previewView = new CameraView(this.$androidContext!, this);
previewView.setTag("9527");
CameraManager.getInstance().setCameraView(previewView);
return previewView;
},
/**
* [可选实现] 原生View已创建
*/
NVLoaded() {
},
/**
* [可选实现] 原生View布局完成
*/
NVLayouted() {
this.$el?.setConfig({
resolution: this.resolution,
frameSize: this.frameSize,
flash: this.flash
} as CameraConfig);
this.$el?.switchCamera(this.position);
},
/**
* [可选实现] 原生View将释放
*/
NVBeforeUnload() {
let ret: Map<string, any> = new Map();
this.$emit('stop', ret);
this.$el?.unbindCamera();
},
/**
* [可选实现] 原生View已释放,这里可以做释放View之后的操作
*/
NVUnloaded() {
CameraManager.getInstance().dispose();
},
/**
* [可选实现] 组件销毁
*/
unmounted() {
},
};
/*
<view>
</view>
*/
//# sourceMappingURL=index.vue.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,183 @@
export type GeneralCallbackResult = {
/** 错误信息 */
errMsg: string;
};
export type TakePhotoSuccessCallbackResult = {
/** 照片文件的临时路径 (本地路径),安卓是jpg图片格式,ios是png */
tempImagePath: string;
quality: string;
errMsg: string;
};
/** 接口调用失败的回调函数 */
export type TakePhotoFailCallback = (res: GeneralCallbackResult) => void;
/** 接口调用成功的回调函数 */
export type TakePhotoSuccessCallback = (result: TakePhotoSuccessCallbackResult) => void;
/** 接口调用结束的回调函数(调用成功、失败都会执行) */
export type TakePhotoCompleteCallback = (res: GeneralCallbackResult) => void;
export type TakePhotoOption = {
/** 接口调用结束的回调函数(调用成功、失败都会执行) */
complete?: TakePhotoCompleteCallback;
/** 接口调用失败的回调函数 */
fail?: TakePhotoFailCallback;
/** 成像质量
*
* 可选值:
* - 'high': 高质量;
* - 'normal': 普通质量;
* - 'low': 低质量;
* - 'original': 原图; */
quality?: 'high' | 'normal' | 'low' | 'original';
/**
* 是否开启镜像 */
selfieMirror?: boolean;
/** 接口调用成功的回调函数 */
success?: TakePhotoSuccessCallback;
};
export type SetZoomSuccessCallbackResult = {
/** 实际设置的缩放级别。由于系统限制,某些机型可能无法设置成指定值,会改用最接近的可设值。 */
zoom: number;
errMsg: string;
};
/** 接口调用结束的回调函数(调用成功、失败都会执行) */
export type SetZoomCompleteCallback = (res: GeneralCallbackResult) => void;
/** 接口调用失败的回调函数 */
export type SetZoomFailCallback = (res: GeneralCallbackResult) => void;
/** 接口调用成功的回调函数 */
export type CameraContextSetZoomSuccessCallback = (result: SetZoomSuccessCallbackResult) => void;
export type CameraContextSetZoomOption = {
/** 缩放级别,范围[1, maxZoom]。zoom 可取小数,精确到小数后一位。maxZoom 可在 bindinitdone 返回值中获取。 */
zoom: number;
/** 接口调用结束的回调函数(调用成功、失败都会执行) */
complete?: SetZoomCompleteCallback;
/** 接口调用失败的回调函数 */
fail?: SetZoomFailCallback;
/** 接口调用成功的回调函数 */
success?: CameraContextSetZoomSuccessCallback;
};
export type StartRecordTimeoutCallbackResult = {
/** 视频的文件的临时路径 (本地路径) */
tempVideoPath: string;
};
/** 接口调用结束的回调函数(调用成功、失败都会执行) */
export type StartRecordCompleteCallback = (res: GeneralCallbackResult) => void;
/** 接口调用失败的回调函数 */
export type StartRecordFailCallback = (res: GeneralCallbackResult) => void;
/** 超过录制时长上限时会结束录像并触发此回调,录像异常退出时也会触发此回调 */
export type StartRecordTimeoutCallback = (result: StartRecordTimeoutCallbackResult) => void;
/** 接口调用成功的回调函数 */
export type CameraContextStartRecordSuccessCallback = (res: GeneralCallbackResult) => void;
export type CameraContextStartRecordOption = {
/** 接口调用结束的回调函数(调用成功、失败都会执行) */
complete?: StartRecordCompleteCallback;
/** 接口调用失败的回调函数 */
fail?: StartRecordFailCallback;
/**
* 是否开启镜像 */
selfieMirror?: boolean;
/** 接口调用成功的回调函数 */
success?: CameraContextStartRecordSuccessCallback;
/**
* 录制时长上限,单位为秒,最长不能超过 5 分钟 */
timeout?: number;
/** 超过录制时长上限时会结束录像并触发此回调,录像异常退出时也会触发此回调 */
timeoutCallback?: StartRecordTimeoutCallback;
};
export type StopRecordSuccessCallbackResult = {
/** 视频的文件的临时路径 (本地路径) */
tempVideoPath: string;
errMsg: string;
};
/** 接口调用结束的回调函数(调用成功、失败都会执行) */
export type StopRecordCompleteCallback = (res: GeneralCallbackResult) => void;
/** 接口调用失败的回调函数 */
export type StopRecordFailCallback = (res: GeneralCallbackResult) => void;
/** 接口调用成功的回调函数 */
export type CameraContextStopRecordSuccessCallback = (result: StopRecordSuccessCallbackResult) => void;
export type CameraContextStopRecordOption = {
/** 接口调用结束的回调函数(调用成功、失败都会执行) */
complete?: StopRecordCompleteCallback;
/** 启动视频压缩,压缩效果同`chooseVideo` */
compressed?: boolean;
/** 接口调用失败的回调函数 */
fail?: StopRecordFailCallback;
/** 接口调用成功的回调函数 */
success?: CameraContextStopRecordSuccessCallback;
};
/** 回调函数 */
export type OnCameraFrameCallback = (result: OnCameraFrameCallbackResult) => void;
export type OnCameraFrameCallbackResult = {
/** 图像像素点数据,一维数组,每四项表示一个像素点的 rgba */
data: any;
/** 图像数据矩形的高度 */
height: number;
/** 图像数据矩形的宽度 */
width: number;
};
/** 接口调用成功的回调函数 */
export type StartSuccessCallback = (res: GeneralCallbackResult) => void;
/** 接口调用失败的回调函数 */
type StartFailCallback = (res: GeneralCallbackResult) => void;
/** 接口调用结束的回调函数(调用成功、失败都会执行) */
type StartCompleteCallback = (res: GeneralCallbackResult) => void;
export type CameraFrameListenerStartOption = {
/** 接口调用结束的回调函数(调用成功、失败都会执行) */
complete?: StartCompleteCallback;
/** 接口调用失败的回调函数 */
fail?: StartFailCallback;
/** 接口调用成功的回调函数 */
success?: StartSuccessCallback;
};
/** 接口调用结束的回调函数(调用成功、失败都会执行) */
export type StopCompleteCallback = (res: GeneralCallbackResult) => void;
/** 接口调用失败的回调函数 */
export type StopFailCallback = (res: GeneralCallbackResult) => void;
/** 接口调用成功的回调函数 */
export type StopSuccessCallback = (res: GeneralCallbackResult) => void;
export type StopOption = {
/** 接口调用结束的回调函数(调用成功、失败都会执行) */
complete?: StopCompleteCallback;
/** 接口调用失败的回调函数 */
fail?: StopFailCallback;
/** 接口调用成功的回调函数 */
success?: StopSuccessCallback;
};
export type FlashMode = 'auto' | 'on' | 'off' | 'torch';
export type DevicePosition = 'back' | 'front';
export type Resolution = 'low' | 'medium' | 'high';
export type FrameSize = 'medium' | 'small' | 'large';
export type QualityType = 'high' | 'normal' | 'low' | 'original';
export type CameraConfig = {
flash?: FlashMode;
devicePosition?: DevicePosition;
resolution?: Resolution;
frameSize?: FrameSize;
};
//////////////////////////////////////////////////////////////////////////////////////////////////
/** 接口调用结束的回调函数(调用成功、失败都会执行) */
export type SwitchCompleteCallback = (res: GeneralCallbackResult) => void;
/** 接口调用失败的回调函数 */
export type SwitchFailCallback = (res: GeneralCallbackResult) => void;
/** 接口调用成功的回调函数 */
export type SwitchSuccessCallback = (res: GeneralCallbackResult) => void;
export type SwitchOption = {
position: DevicePosition;
/** 接口调用结束的回调函数(调用成功、失败都会执行) */
complete?: SwitchCompleteCallback;
/** 接口调用失败的回调函数 */
fail?: SwitchFailCallback;
/** 接口调用成功的回调函数 */
success?: SwitchSuccessCallback;
};
//////////////////////////////////////////////////////////////////////////////////////////////////
export type OnCameraFrameListenerOption = {
success?: OnCameraFrameCallback;
};
export type TakePhoto = (options: TakePhotoOption) => void;
export type SetZoom = (options: CameraContextSetZoomOption) => void;
export type StartRecord = (options: CameraContextStartRecordOption) => void;
export type StopRecord = (options: CameraContextStopRecordOption) => void;
export type OnCameraFrameListener = (options: OnCameraFrameListenerOption) => void;
export type StartCameraFrame = (options: CameraFrameListenerStartOption) => void;
export type StopCameraFrame = (options: StopOption) => void;
export type SwitchCamera = (options: SwitchOption) => void;
//# sourceMappingURL=interface.uts.map
File diff suppressed because one or more lines are too long