success
This commit is contained in:
+34
@@ -0,0 +1,34 @@
|
||||
let firstBackTime = 0;
|
||||
const __sfc__ = defineApp({
|
||||
onLaunch() {
|
||||
console.log('App Launch');
|
||||
},
|
||||
onShow() {
|
||||
console.log('App Show');
|
||||
},
|
||||
onHide() {
|
||||
console.log('App Hide');
|
||||
},
|
||||
onLastPageBackPress() {
|
||||
console.log('App LastPageBackPress');
|
||||
if (firstBackTime == 0) {
|
||||
uni.showToast({
|
||||
title: '再按一次退出应用',
|
||||
position: 'bottom',
|
||||
});
|
||||
firstBackTime = Date.now();
|
||||
setTimeout(() => {
|
||||
firstBackTime = 0;
|
||||
}, 2000);
|
||||
}
|
||||
else if (Date.now() - firstBackTime < 2000) {
|
||||
firstBackTime = Date.now();
|
||||
uni.exit();
|
||||
}
|
||||
},
|
||||
onExit() {
|
||||
console.log('App Exit');
|
||||
},
|
||||
});
|
||||
export default __sfc__;
|
||||
const GenAppStyles = [_uM([["uni-row", _pS(_uM([["flexDirection", "row"]]))], ["uni-column", _pS(_uM([["flexDirection", "column"]]))]])];
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
import App from './App.uvue';
|
||||
import { createSSRApp } from 'vue';
|
||||
export function createApp(): UTSJSONObject {
|
||||
const app = createSSRApp(App);
|
||||
return {
|
||||
app
|
||||
};
|
||||
}
|
||||
export function main(app: IApp) {
|
||||
definePageRoutes();
|
||||
defineAppConfig();
|
||||
(createApp()['app'] as VueApp).mount(app, GenUniApp());
|
||||
}
|
||||
export class UniAppConfig extends io.dcloud.uniapp.appframe.AppConfig {
|
||||
override name: string = "SkinCamera";
|
||||
override appid: string = "__UNI__644401D";
|
||||
override versionName: string = "1.0.0";
|
||||
override versionCode: string = "100";
|
||||
override uniCompilerVersion: string = "4.87";
|
||||
constructor() { super(); }
|
||||
}
|
||||
import GenPagesIndexIndexClass from './pages/index/index.uvue';
|
||||
function definePageRoutes() {
|
||||
__uniRoutes.push({ path: "pages/index/index", component: GenPagesIndexIndexClass, meta: { isQuit: true } as UniPageMeta, style: _uM([["navigationBarTitleText", "uni-app x"]]) } as UniPageRoute);
|
||||
}
|
||||
const __uniTabBar: Map<string, any | null> | null = null;
|
||||
const __uniLaunchPage: Map<string, any | null> = _uM([["url", "pages/index/index"], ["style", _uM([["navigationBarTitleText", "uni-app x"]])]]);
|
||||
function defineAppConfig() {
|
||||
__uniConfig.entryPagePath = '/pages/index/index';
|
||||
__uniConfig.globalStyle = _uM([["navigationBarTextStyle", "black"], ["navigationBarTitleText", "uni-app x"], ["navigationBarBackgroundColor", "#F8F8F8"], ["backgroundColor", "#F8F8F8"]]);
|
||||
__uniConfig.getTabBarConfig = (): Map<string, any> | null => null;
|
||||
__uniConfig.tabBar = __uniConfig.getTabBarConfig();
|
||||
__uniConfig.conditionUrl = '';
|
||||
__uniConfig.uniIdRouter = _uM();
|
||||
__uniConfig.ready = true;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import { takePhoto, TakePhotoOption, TakePhotoSuccessCallbackResult, GeneralCallbackResult } from '@/uni_modules/Skin-cameraUTS';
|
||||
const __sfc__ = defineComponent({
|
||||
data() {
|
||||
return {
|
||||
yanse: "red",
|
||||
widthNum: 750,
|
||||
heightNum: 200,
|
||||
flash: "on",
|
||||
device: "front",
|
||||
imagePath: "",
|
||||
videoPath: "https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/2minute-demo.mp4"
|
||||
};
|
||||
},
|
||||
onLoad() {
|
||||
// let permissionNeed = ["android.permission.CAMERA", "android.permission.RECORD_AUDIO",
|
||||
// "android.permission.WRITE_EXTERNAL_STORAGE"]
|
||||
// // 请求权限
|
||||
// UTSAndroid.requestSystemPermission(UTSAndroid.getUniActivity()!, permissionNeed, function (allRight : boolean, _ : string[]) {
|
||||
// if (allRight) {
|
||||
// // 权限请求成功
|
||||
// } else {
|
||||
// //用户拒绝了部分权限
|
||||
// }
|
||||
// }, function (_ : boolean, _ : string[]) {
|
||||
// //用户拒绝了部分权限
|
||||
// })
|
||||
},
|
||||
methods: {
|
||||
onError(res: any) {
|
||||
console.log(res);
|
||||
},
|
||||
_takePhoto() {
|
||||
takePhoto({
|
||||
success: (res: TakePhotoSuccessCallbackResult) => {
|
||||
console.log('takePhoto', res);
|
||||
this.imagePath = res.tempImagePath;
|
||||
// _previewImage();
|
||||
},
|
||||
fail: (res: GeneralCallbackResult) => {
|
||||
console.log('takePhoto', res);
|
||||
}
|
||||
} as TakePhotoOption);
|
||||
}
|
||||
}
|
||||
});
|
||||
export default __sfc__;
|
||||
function GenPagesIndexIndexRender(this: InstanceType<typeof __sfc__>): any | null {
|
||||
const _ctx = this;
|
||||
const _cache = this.$.renderCache;
|
||||
return _cE("scroll-view", _uM({ class: "page-scroll-view" }), [
|
||||
_cE("view", null, [
|
||||
_cE("button", _uM({ onClick: _ctx._takePhoto }), "拍照", 8 /* PROPS */, ["onClick"]),
|
||||
_cE(XfCameraComponent.name, _uM({
|
||||
style: _nS(_uM({ "height": "750rpx", "background-color": "red" })),
|
||||
onError: _ctx.onError,
|
||||
flash: _ctx.flash,
|
||||
position: _ctx.device
|
||||
}), null, 44 /* STYLE, PROPS, NEED_HYDRATION */, ["onError", "flash", "position"]),
|
||||
isTrue(_ctx.imagePath)
|
||||
? _cE("image", _uM({
|
||||
key: 0,
|
||||
mode: "aspectFit",
|
||||
src: _ctx.imagePath
|
||||
}), null, 8 /* PROPS */, ["src"])
|
||||
: _cC("v-if", true)
|
||||
])
|
||||
]);
|
||||
}
|
||||
const GenPagesIndexIndexStyles = [_uM([["video", _pS(_uM([["width", "100%"], ["height", 200]]))]])];
|
||||
import { XfCameraComponent } from '@/uni_modules/Skin-cameraUTS?uts-proxy';
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Vendored
+414
@@ -0,0 +1,414 @@
|
||||
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
|
||||
// }
|
||||
Vendored
+214
@@ -0,0 +1,214 @@
|
||||
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(() => {
|
||||
console.log("未找到相机");
|
||||
});
|
||||
}
|
||||
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);
|
||||
};
|
||||
Vendored
+140
@@ -0,0 +1,140 @@
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
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>
|
||||
*/
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user