相机demo:import { abilityAccessCtrl, PermissionRequestResult, Permissions } from '@kit.AbilityKit'; import { BusinessError } from '@kit.BasicServicesKit'; import { promptAction, router } from '@kit.ArkUI'; import { image } from '@kit.ImageKit'; import { photoAccessHelper } from '@kit.MediaLibraryKit'; import { fileIo } from '@kit.CoreFileKit'; import { camera } from '@kit.CameraKit'; @Entry @Component struct PhotoDemo { context: Context = getContext(this) as Context; @State hasPicture: boolean = false; @State finalPixelMap: image.PixelMap | undefined = undefined; // 设置安全控件按钮属性 @State saveButtonOptions: SaveButtonOptions = { icon: SaveIconStyle.FULL_FILLED, text: SaveDescription.SAVE_IMAGE, buttonType: ButtonType.Capsule } @State buffer: ArrayBuffer | undefined = undefined; @State surfaceId: string = ''; @State imageSize: image.Size = { width: 1920, height: 1080 }; private mXComponentController: XComponentController = new XComponentController; private cameraManager: camera.CameraManager | undefined = undefined; private cameraInput: camera.CameraInput | undefined = undefined; private photoOutput: camera.PhotoOutput | undefined = undefined; private previewOutput: camera.PreviewOutput | undefined = undefined; private cameraSession: camera.PhotoSession | undefined = undefined; aboutToAppear(): void { let permissions: Array<Permissions> = [ 'ohos.permission.CAMERA', 'ohos.permission.WRITE_MEDIA', 'ohos.permission.READ_MEDIA', 'ohos.permission.MEDIA_LOCATION' ]; let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗 atManager.requestPermissionsFromUser(this.context, permissions).then((data: PermissionRequestResult) => { let grantStatus: Array<number> = data.authResults; let length: number = grantStatus.length; for (let i = 0; i < length; i++) { if (grantStatus[i] != 0) { // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限 return; } } console.info(`${TAG} Success to request permissions from user. authResults is ${grantStatus}.`); }).catch((err: BusinessError) => { console.error(`${TAG} Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`); }) } build() { Column() { //设置返回键 Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Start }) { Image($r('app.media.ic_public_back')) .width(30) .onClick(() => { router.back() }) } //预览框 Column({ space: 20 }) { if (this.hasPicture) { Image(this.finalPixelMap) .objectFit(ImageFit.Fill) .width('100%') .height(300) SaveButton(this.saveButtonOptions)// 创建安全控件按钮 .onClick(async (event, result: SaveButtonOnClickResult) => { if (result == SaveButtonOnClickResult.SUCCESS) { if (this.finalPixelMap) { try { // 1、使用安全控件创建文件 let phAccessHelper: photoAccessHelper.PhotoAccessHelper = photoAccessHelper.getPhotoAccessHelper(this.context); let options: photoAccessHelper.CreateOptions = { title: Date.now().toString() }; // createAsset的调用需要ohos.permission.READ_IMAGEVIDEO和ohos.permission.WRITE_IMAGEVIDEO的权限 let photoUri: string = await phAccessHelper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'png', options); console.info('CameraDemo createAsset successfully, photoUri: ' + photoUri); // 2.1、方式一:通过文件管理写入文件 let file: fileIo.File = fileIo.openSync(photoUri, fileIo.OpenMode.WRITE_ONLY); fileIo.writeSync(file.fd, this.buffer); fileIo.closeSync(file); promptAction.showToast({message: `保存成功`}) } catch (error) { let err = error as BusinessError; console.error(`CameraDemo savePicture error: ${JSON.stringify(err)}`); promptAction.showToast({ message: `保存失败` }) } } } else { console.error('CameraDemo SaveButtonOnClickResult createAsset failed.'); promptAction.showToast({ message: `保存失败` }) } setTimeout(() => { this.hasPicture = false; this.finalPixelMap = undefined; }, 1000) }) } else { XComponent({ id: '', type: 'surface', libraryname: '', controller: this.mXComponentController }) .onLoad(() => { // 设置Surface宽高(1920*1080),预览尺寸设置参考previewProfilesArray获取的当前设备所支持的预览分辨率大小去设置 // 预览流与录像输出流的分辨率的宽高比要保持一致 this.mXComponentController.setXComponentSurfaceSize({ surfaceWidth: 1920, surfaceHeight: 1080 }); // 获取Surface ID this.surfaceId = this.mXComponentController.getXComponentSurfaceId(); setTimeout(async () => { await this.prepareCamera(); }, 500); }) .width('100%') .height(300) Button('拍照') .width(200) .height(30) .onClick(async () => { //设置拍照参数 let photoCaptureSetting: camera.PhotoCaptureSetting = { quality: camera.QualityLevel.QUALITY_LEVEL_HIGH, // 设置图片质量高 rotation: camera.ImageRotation.ROTATION_0 // 设置图片旋转角度0 } //通过拍照流实现:点击拍照 await this.photoOutput?.capture(photoCaptureSetting).catch((error: BusinessError) => { console.error(`CameraDemo Failed to capture the photo ${error.message}`); //不符合条件则进入 }) this.hasPicture = true; }) } } .width('100%') .height('100%') .padding(15) .borderRadius(8) } .width('100%') .height('100%') .backgroundColor('#FFFFFF') } // 创建CameraManager对象 createCameraManager() { let cameraManager: camera.CameraManager = camera.getCameraManager(this.context); if (!cameraManager) { console.error('CameraDemo camera.getCameraManager error'); return; } this.cameraManager = cameraManager; // 监听相机状态变化 this.cameraManager.on('cameraStatus', (err: BusinessError, cameraStatusInfo: camera.CameraStatusInfo) => { console.info(`CameraDemo camera: ${cameraStatusInfo.camera.cameraId}, status: ${cameraStatusInfo.status}`); }); } //函数中设置监听photoAvailable,在回调中生成图片 setPhotoOutputCb(photoOutput: camera.PhotoOutput) { //设置回调之后,调用photoOutput的capture方法,就会将拍照的buffer回传到回调中 photoOutput.on('photoAvailable', (errCode: BusinessError, photo: camera.Photo): void => { console.info(`CameraDemo getPhoto start. err: ${JSON.stringify(errCode)}`); if (errCode || photo === undefined || photo.main === undefined) { console.error('CameraDemo getPhoto failed'); return; } let imageObj = photo.main; imageObj.getComponent(image.ComponentType.JPEG, async (errCode: BusinessError, component: image.Component): Promise<void> => { console.info('CameraDemo getComponent start'); if (errCode || component === undefined) { console.error('CameraDemo getComponent failed'); return; } let buffer: ArrayBuffer; if (component.byteBuffer) { buffer = component.byteBuffer; this.buffer = buffer; let sourceOptions: image.SourceOptions = { sourceDensity: 0, // 在不确定当前密度时传0 sourcePixelFormat: image.PixelMapFormat.RGBA_8888, sourceSize: this.imageSize } let imageSource: image.ImageSource = image.createImageSource(buffer, sourceOptions); let opts: image.InitializationOptions = { editable: false, pixelFormat: image.PixelMapFormat.RGBA_8888, size: this.imageSize } let pixelMap = await imageSource.createPixelMap(opts); this.finalPixelMap = pixelMap; } else { console.error('CameraDemo byteBuffer is null'); return; } }); }); } //相机准备 async prepareCamera() { this.createCameraManager(); if (!this.cameraManager) { console.error('CameraDemo cameraManager is undefined.') return; } // 获取设备支持的相机对象,根据位置可划分后置,前置,折叠态相机 let cameraDevices: Array<camera.CameraDevice> = []; try { cameraDevices = this.cameraManager.getSupportedCameras(); } catch (error) { let err = error as BusinessError; console.error(`CameraDemo The getSupportedCameras call failed. error: ${JSON.stringify(err)}`) } cameraDevices.forEach((cameraDevice: camera.CameraDevice) => { console.info(`CameraDemo cameraId: ${cameraDevice.cameraId}, cameraPosition: ${cameraDevice.cameraPosition.toString()}, cameraType: ${cameraDevice.cameraType.toString()}, connectionType: ${cameraDevice.connectionType.toString()}`) }) // 获取设备支持的具体某个相机对象的支持的模式类型,包含普通拍照及普通录像两种模式,cameraDevices[0]代表后置相机 let cameraSceneModes: Array<camera.SceneMode> = []; try { cameraSceneModes = this.cameraManager.getSupportedSceneModes(cameraDevices[1]); cameraSceneModes.forEach((cameraSceneMode: camera.SceneMode) => { console.info(`CameraDemo cameraSceneMode: ${cameraSceneMode.toString()}`) }) //判断支持的模式类型是否包含拍照 let isSupportPhotoMode: boolean = cameraSceneModes.indexOf(camera.SceneMode.NORMAL_PHOTO) >= 0; if (!isSupportPhotoMode) { console.error('CameraDemo photo mode not support'); return; } } catch (error) { let err = error as BusinessError; console.error(`CameraDemo The getSupportedSceneModes call failed. error: ${JSON.stringify(err)}`) } // 创建相机输入流 try { this.cameraInput = this.cameraManager.createCameraInput(cameraDevices[1]); } catch (error) { let err = error as BusinessError; console.error(`CameraDemo createCaptureSession error. error: ${JSON.stringify(err)}`); return } // 监听cameraInput错误信息 this.cameraInput.on('error', cameraDevices[1], (error: BusinessError) => { console.error(`CameraDemo Camera input error: ${JSON.stringify(error)}`); }); // 打开相机 try { await this.cameraInput.open(); } catch (error) { let err = error as BusinessError; console.error(`CameraDemo cameraInput open error. error: ${JSON.stringify(err)}`); } // 获取相机对象支持的输出流能力,包含预览,拍照,录像等信息 let cameraOutputCapability: camera.CameraOutputCapability = this.cameraManager.getSupportedOutputCapability(cameraDevices[1], camera.SceneMode.NORMAL_PHOTO) if (!cameraOutputCapability) { console.error('CameraDemo cameraManager.getSupportedOutputCapability error'); return; } //获取当前设备支持的预览能力 let previewProfile = cameraOutputCapability.previewProfiles[0]; //预览流和相片分辨率的宽高比要保持一致 cameraOutputCapability.previewProfiles.forEach((profile) => { if (profile.size.width == this.imageSize.width && profile.size.height == this.imageSize.height) { previewProfile = profile; return; } }) this.imageSize = previewProfile.size; // 创建相机预览输出流 try { this.previewOutput = this.cameraManager.createPreviewOutput(previewProfile, this.surfaceId); } catch (error) { let err = error as BusinessError; console.error(`CameraDemo createCaptureSession error. error: ${JSON.stringify(err)}`); return } // 监听previewOutput错误信息 this.previewOutput.on('error', (error: BusinessError) => { console.error(`CameraDemo previewOutput error: ${JSON.stringify(error)}`); }); try { //获取当前设备支持的拍照能力 let photoProfile = cameraOutputCapability.photoProfiles[0]; //拍照流和相片分辨率的宽高比要保持一致 cameraOutputCapability.photoProfiles.forEach((profile) => { if (profile.size.width == this.imageSize.width && profile.size.height == this.imageSize.height) { photoProfile = profile; return; } }) //创建相机拍照输出流 this.photoOutput = this.cameraManager.createPhotoOutput(photoProfile); } catch (error) { let err = error as BusinessError; console.error(`CameraDemo createPhotoOutput error ${JSON.stringify(err)}`); } if (this.photoOutput === undefined) { console.error('CameraDemo photoOutput is undefined.'); return; } //调用自定义函数,在定义的监听的回调中保存图片,该自定义函数需传参拍照输出流 this.setPhotoOutputCb(this.photoOutput); //创建相机会话 try { this.cameraSession = this.cameraManager.createSession(camera.SceneMode.NORMAL_PHOTO) as camera.PhotoSession; } catch (error) { let err = error as BusinessError; console.error(`CameraDemo createCaptureSession error. error: ${JSON.stringify(err)}`); return } // 监听session错误信息 this.cameraSession.on('error', (error: BusinessError) => { console.error(`CameraDemo Capture session error: ${JSON.stringify(error)}`); }); // 开始配置会话 try { this.cameraSession.beginConfig() } catch (error) { let err = error as BusinessError; console.error(`CameraDemo beginConfig error. error: ${JSON.stringify(err)}`); } // 向会话中添加相机输入流 try { this.cameraSession.addInput(this.cameraInput) } catch (error) { let err = error as BusinessError; console.error(`CameraDemo addInput error. error: ${JSON.stringify(err)}`); } // 向会话中添加预览输出流 try { this.cameraSession.addOutput(this.previewOutput) } catch (error) { let err = error as BusinessError; console.error(`CameraDemo add previewOutput error. error: ${JSON.stringify(err)}`); } // 向会话中添加拍照输出流 try { this.cameraSession.addOutput(this.photoOutput); } catch (error) { let err = error as BusinessError; console.error(`CameraDemo add photoOutput error. error: ${JSON.stringify(err)}`); } // 提交会话配置 try { await this.cameraSession.commitConfig(); } catch (error) { let err = error as BusinessError; console.error(`CameraDemo captureSession commitConfig error: ${JSON.stringify(err)}`); } // 启动会话 try { await this.cameraSession.start(); } catch (error) { let err = error as BusinessError; console.error(`CameraDemo captureSession start error: ${JSON.stringify(err)}`); } //调用自定义函数,配置相机的参数,传参相机会话 this.configuringSession(this.cameraSession) } //配置相机的参数可以调整拍照的一些功能,包括闪光灯、变焦、焦距等 configuringSession(photoSession: camera.PhotoSession): void { // 判断设备是否支持闪光灯 let flashStatus: boolean = false; try { flashStatus = photoSession.hasFlash(); } catch (error) { let err = error as BusinessError; console.error(`CameraDemo Failed to hasFlash. error: ${JSON.stringify(err)}`); } console.info(`CameraDemo Returned with the flash light support status: ${flashStatus}`); if (flashStatus) { // 判断是否支持自动闪光灯模式 let flashModeStatus: boolean = false; try { let status: boolean = photoSession.isFlashModeSupported(camera.FlashMode.FLASH_MODE_AUTO); flashModeStatus = status; } catch (error) { let err = error as BusinessError; console.error(`CameraDemo Failed to check whether the flash mode is supported. error: ${JSON.stringify(err)}`); } if (flashModeStatus) { // 设置自动闪光灯模式 try { photoSession.setFlashMode(camera.FlashMode.FLASH_MODE_AUTO); } catch (error) { let err = error as BusinessError; console.error(`CameraDemo Failed to set the flash mode. error: ${JSON.stringify(err)}`); } } } // 判断是否支持连续自动变焦模式 let focusModeStatus: boolean = false; try { let status: boolean = photoSession.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO); focusModeStatus = status; } catch (error) { let err = error as BusinessError; console.error(`CameraDemo Failed to check whether the focus mode is supported. error: ${JSON.stringify(err)}`); } if (focusModeStatus) { // 设置连续自动变焦模式 try { photoSession.setFocusMode(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO); } catch (error) { let err = error as BusinessError; console.error(`CameraDemo Failed to set the focus mode. error: ${JSON.stringify(err)}`); } } // 获取相机支持的可变焦距比范围 let zoomRatioRange: Array<number> = []; try { zoomRatioRange = photoSession.getZoomRatioRange(); } catch (error) { let err = error as BusinessError; console.error(`CameraDemo Failed to get the zoom ratio range. error: ${JSON.stringify(err)}`); } if (zoomRatioRange.length <= 0) { return; } // 设置可变焦距比 try { photoSession.setZoomRatio(zoomRatioRange[0]); } catch (error) { let err = error as BusinessError; console.error(`CameraDemo Failed to set the zoom ratio value. error: ${JSON.stringify(err)}`); } } }
相机demo: