daShangDao_scanBook/uni_modules/lime-camera/utssdk/app-harmony/builder.ets

372 lines
12 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit';
import { camera } from '@kit.CameraKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { image } from '@kit.ImageKit';
import fs from '@ohos.file.fs';
@Component
struct CameraViewComponent {
@Prop mode: string = 'photo'
@Prop isFront: boolean = false
@Prop isFlash: boolean = false
@Prop isTorch: boolean = false
@Prop correctOrientation: boolean = false
@Prop @Watch('onCommandChange') command: string = '' // 指令
onTake?: (path: string) => void
private xComponentCtl: XComponentController = new XComponentController();
private xComponentSurfaceId: string = '';
@State imageWidth: number = 1920;
@State imageHeight: number = 1080;
private cameraManager: camera.CameraManager | undefined = undefined;
private cameras: Array<camera.CameraDevice> | Array<camera.CameraDevice> = [];
private cameraPosition: number = 0
private isFrontCamera = false
private cameraInput: camera.CameraInput | undefined = undefined;
private previewOutput: camera.PreviewOutput | undefined = undefined;
private photoOutput: camera.PhotoOutput | undefined = undefined;
private videoSession: camera.VideoSession | undefined = undefined;
private photoSession: camera.PhotoSession | undefined = undefined;
private uiContext: UIContext = this.getUIContext();
private context: Context | undefined = this.uiContext.getHostContext();
private cameraPermission: Permissions = 'ohos.permission.CAMERA';
private isTorchOn: boolean = false
private isFlashOn: boolean = false
@State isShow: boolean = false;
onCommandChange() {
let command = this.command.split('-')[0]
if (command == 'open') {
this.initCamera()
} else if (command == 'close') {
this.releaseCamera();
} else if (command == 'take') {
this.takePhoto()
} else if (command == 'switch') {
this.isFrontCamera = this.isFront
this.switchCamera()
} else if (command == 'flash') {
this.isFlashOn = this.isFlash
this.onFlash()
} else if (command == 'torch') {
this.isTorchOn = this.isTorch
this.onTorch()
}
}
async requestPermissionsFn(): Promise<void> {
let atManager = abilityAccessCtrl.createAtManager();
if (this.context) {
let res = await atManager.requestPermissionsFromUser(this.context, [this.cameraPermission]);
for (let i = 0; i < res.permissions.length; i++) {
if (this.cameraPermission.toString() === res.permissions[i] && res.authResults[i] === 0) {
this.isShow = true;
}
}
}
}
async aboutToAppear() {
await this.requestPermissionsFn();
}
aboutToDisappear(): void {
this.releaseCamera();
}
// 初始化相机。
async initCamera(): Promise<void> {
// console.info(`initCamera previewOutput xComponentSurfaceId:${this.xComponentSurfaceId}`);
try {
// 获取相机管理器实例。
this.cameraManager = camera.getCameraManager(this.context);
if (!this.cameraManager) {
console.error('initCamera getCameraManager');
}
// 获取当前设备支持的相机device列表。
this.cameras = this.cameraManager.getSupportedCameras();
if (!this.cameras) {
console.error('initCamera getSupportedCameras');
}
// 选择一个相机device创建cameraInput输出对象。
this.cameraInput = this.cameraManager.createCameraInput(this.cameras[this.cameraPosition]);
if (!this.cameraInput) {
console.error('initCamera createCameraInput');
}
// 打开相机。
await this.cameraInput.open().catch((err: BusinessError) => {
console.error(`initCamera open fail: ${err}`);
})
// 获取相机device支持的profile。
let capability: camera.CameraOutputCapability = this.cameraManager.getSupportedOutputCapability(this.cameras[this.cameraPosition], camera.SceneMode.NORMAL_PHOTO);
if (!capability) {
console.error('initCamera getSupportedOutputCapability');
}
let previewProfilesArray: Array<camera.Profile> = capability.previewProfiles;
if (!previewProfilesArray) {
console.error("createOutput previewProfilesArray == null || undefined");
}
let photoProfilesArray: Array<camera.Profile> = capability.photoProfiles;
if (!photoProfilesArray) {
console.error("createOutput photoProfilesArray == null || undefined");
}
// 预览
let minRatioDiff: number = 0.1;
let surfaceRatio: number = this.imageWidth / this.imageHeight; // 最接近16:9宽高比。
let previewProfile: camera.Profile = previewProfilesArray[0];
// // 应用开发者根据实际业务需求选择一个支持的预览流previewProfile。
// for (let index = 0; index < previewProfilesArray.length; index++) {
// const tempProfile = previewProfilesArray[index];
// let tempRatio = tempProfile.size.width >= tempProfile.size.height ?
// tempProfile.size.width / tempProfile.size.height : tempProfile.size.height / tempProfile.size.width;
// let currentRatio = Math.abs(tempRatio - surfaceRatio);
// if (currentRatio <= minRatioDiff && tempProfile.format == camera.CameraFormat.CAMERA_FORMAT_JPEG) {
// previewProfile = tempProfile;
// break;
// }
// }
// this.imageWidth = previewProfile.size.width; // 更新xComponent组件的宽。
// this.imageHeight = previewProfile.size.height; // 更新xComponent组件的高。
// console.info(`initCamera imageWidth:${this.imageWidth} imageHeight:${this.imageHeight}`);
// 使用xComponentSurfaceId创建预览。
this.previewOutput = this.cameraManager.createPreviewOutput(previewProfile, this.xComponentSurfaceId);
if (!this.previewOutput) {
console.error('initCamera createPreviewOutput');
}
// 拍照
this.photoOutput = this.cameraManager.createPhotoOutput(photoProfilesArray[0]);
this.setPhotoOutputCb(this.photoOutput);
// 创建录像模式相机会话。
if(this.mode == 'video') {
this.videoSession = this.cameraManager.createSession(camera.SceneMode.NORMAL_VIDEO) as camera.VideoSession;
if (!this.videoSession) {
console.error('initCamera createSession');
}
// 开始配置会话。
this.videoSession.beginConfig();
// 添加相机设备输入。
this.videoSession.addInput(this.cameraInput);
// 添加预览流输出。
this.videoSession.addOutput(this.previewOutput);
// 提交会话配置。
await this.videoSession.commitConfig();
// 开始启动已配置的输入输出流。
await this.videoSession.start();
} else if(this.mode == 'photo') {
this.photoSession = this.cameraManager.createSession(camera.SceneMode.NORMAL_PHOTO) as camera.PhotoSession;
if (!this.photoSession) {
console.error('initCamera createSession');
}
// 开始配置会话。
this.photoSession.beginConfig();
// 添加相机设备输入。
this.photoSession.addInput(this.cameraInput);
// 添加预览流输出。
this.photoSession.addOutput(this.previewOutput);
// 添加拍照输出流
this.photoSession.addOutput(this.photoOutput);
// 提交会话配置。
await this.photoSession.commitConfig();
// 开始启动已配置的输入输出流。
await this.photoSession.start();
}
} catch (error) {
console.error(`initCamera fail: ${error}`);
}
}
// 释放相机。
async releaseCamera(): Promise<void> {
try {
if(this.mode == 'video') {
// 停止当前会话。
await this.videoSession?.stop();
// 释放相机输入流。
await this.cameraInput?.close();
// 释放预览输出流。
await this.previewOutput?.release();
// 释放会话。
await this.videoSession?.release();
} else if(this.mode == 'photo') {
// 停止当前会话。
await this.photoSession?.stop();
// 释放相机输入流。
await this.cameraInput?.close();
// 释放预览输出流。
await this.previewOutput?.release();
// 释放拍照输出流。
await this.photoOutput?.release();
// 释放会话。
await this.photoSession?.release();
}
} catch (error) {
console.error(`initCamera fail: ${error}`);
}
}
setPhotoOutputCb(photoOutput: camera.PhotoOutput): void {
//设置回调之后调用photoOutput的capture方法就会将拍照的buffer回传到回调中。
photoOutput.on('photoAvailable', (errCode: BusinessError, photo: camera.Photo): void => {
if (errCode || photo === undefined) {
console.error('getPhoto failed');
return;
}
let imageObj = photo.main;
imageObj.getComponent(image.ComponentType.JPEG, async (errCode: BusinessError, component: image.Component) => {
if (errCode || component === undefined) {
console.error('getComponent failed');
return;
}
let buffer: ArrayBuffer;
if (component.byteBuffer) {
buffer = component.byteBuffer;
} else {
console.error('byteBuffer is null');
return;
}
// 生成照片
try {
const tempDir = this.context?.cacheDir;
const timestamp = new Date().getTime();
const fileName = `photo_${timestamp}.jpg`;
const filePath = `${tempDir}/${fileName}`;
const file = await fs.open(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
await fs.write(file.fd, buffer);
await fs.close(file.fd);
this.onTake?.(filePath);
} catch (error) {
console.error('保存临时照片失败:', error);
} finally {
imageObj.release();
}
});
});
}
takePhoto() {
let photoCaptureSetting: camera.PhotoCaptureSetting = {
quality: camera.QualityLevel.QUALITY_LEVEL_HIGH, // 设置图片质量高。
rotation: camera.ImageRotation.ROTATION_0 // 设置图片旋转角度0。
}
// 使用当前拍照设置进行拍照。
this.photoOutput?.capture(photoCaptureSetting, (err: BusinessError) => {
if (err) {
console.error(`Failed to capture the photo ${err.message}`);
return;
}
// console.info('Callback invoked to indicate the photo capture request success.');
});
}
// 切换摄像头
async switchCamera() {
if (this.cameras.length < 2) {
console.error('Only one camera available');
return;
}
// 切换摄像头位置
this.cameraPosition = (this.isFrontCamera
? camera.CameraPosition.CAMERA_POSITION_FRONT
: camera.CameraPosition.CAMERA_POSITION_BACK) - 1;
await this.releaseCamera();
await this.initCamera();
}
// 手电筒
onTorch() {
try {
let torchSupport = this.cameraManager?.isTorchSupported() ?? false
if(torchSupport) {
if(this.cameraPosition == camera.CameraPosition.CAMERA_POSITION_BACK - 1) {
console.error('back camera not support');
return
}
this.cameraManager?.setTorchMode(this.isTorchOn ? camera.TorchMode.ON : camera.TorchMode.OFF);
}
} catch (error) {
console.error(error);
}
}
// 闪光灯
onFlash() {
try {
let torchSupport = this.cameraManager?.isTorchSupported() ?? false
if(torchSupport) {
if(this.cameraPosition == camera.CameraPosition.CAMERA_POSITION_FRONT - 1) {
console.error('front camera not support');
return
}
this.cameraManager?.setTorchMode(this.isFlashOn ? camera.TorchMode.AUTO : camera.TorchMode.OFF);
}
} catch (error) {
console.error(error);
}
}
build() {
Column() {
if (this.isShow) {
XComponent({
id: 'componentId',
type: XComponentType.SURFACE,
controller: this.xComponentCtl
})
.onLoad(async () => {
// 获取组件surfaceId。
this.xComponentSurfaceId = this.xComponentCtl.getXComponentSurfaceId();
// 初始化相机,组件实时渲染每帧预览流数据。
this.initCamera()
})
.width(this.uiContext.px2vp(this.imageHeight))
.height(this.uiContext.px2vp(this.imageWidth))
}
}
.justifyContent(FlexAlign.Center)
.backgroundColor(Color.Black)
.height('100%')
.width('100%')
}
}
@Builder
export function CameraView(params: ESObject) {
Row() {
CameraViewComponent({
mode: 'photo',
isFront: params.isFront,
isFlash: params.isFlash,
isTorch: params.isTorch,
command: params.command,
correctOrientation: params.correctOrientation,
onTake: (path: string) => {
let fun = params.onTake as (path: string) => void
fun(path)
}
})
.width('100%')
.height('100%')
}
.width('100%')
.height('100%')
.attributeModifier(params.attributeUpdater)
}