相机开发:CameraKit调用摄像头与拍照预览(36) 在 HarmonyOS 中开发相机应用开发者可以根据业务需求选择两种不同的技术路线如果仅需获取即时拍摄的照片或视频推荐使用CameraPicker相机选择器如果需要构建高度自定义的相机应用或实现实时预览分析则需要使用Camera Kit 核心 API。以下是这两种方式的完整开发流程与实战代码一、 方案一使用 CameraPicker 快速调用系统相机CameraPicker 由系统提供交互界面用户主动点击拍摄并确认后应用即可获取结果。此方案无需申请相机权限开发极其简便。核心代码示例import { camera, cameraPicker as picker } from kit.CameraKit; import { fileIo, fileUri } from kit.CoreFileKit; // 1. 配置 PickerProfile指定保存路径或默认存入媒体库 let pickerProfile: picker.PickerProfile { cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK, // 若不配置 saveUri照片/视频默认存入媒体库 }; // 2. 调用 picker 接口获取拍摄结果 async function getPickerResult(context: Context): Promisepicker.PickerResult { let result await picker.pick( context, [picker.PickerMediaType.PHOTO, picker.PickerMediaType.VIDEO], pickerProfile ); console.info(resultCode: ${result.resultCode}, resultUri: ${result.resultUri}); return result; }二、 方案二使用 Camera Kit 实现自定义预览与拍照构建自定义相机需要严格遵循“权限申请 - 创建输入输出流 - 会话管理 - 启动预览”的流程。1. 权限配置与动态申请相机属于敏感权限必须在module.json5中声明并在运行时动态申请requestPermissions: [ { name: ohos.permission.CAMERA } ]在代码中使用abilityAccessCtrl.createAtManager().requestPermissionsFromUser()向用户申请授权。2. 获取相机设备与创建输入流import { camera } from kit.CameraKit; // 获取相机管理器并获取支持的相机设备列表 let cameraManager camera.getCameraManager(context); let cameraDevices cameraManager.getSupportedCameras(); // 获取后置摄像头并创建输入流 let cameraDevice cameraDevices.find(device device.cameraPosition camera.CameraPosition.CAMERA_POSITION_BACK ); let cameraInput cameraManager.createCameraInput(cameraDevice); await cameraInput.open(); // 打开相机3. 创建预览 Surface 与输出流预览画面必须通过XComponent组件渲染并获取其surfaceId绑定到预览输出流// UI 层声明 XComponent XComponent({ type: XComponentType.SURFACE, controller: this.xComponentController }) .onLoad(async () { // 获取 surfaceId let surfaceId this.xComponentController.getXComponentSurfaceId(); // 获取设备支持的预览分辨率注意宽高比需与 XComponent 保持一致 let cameraOutputCapability cameraManager.getSupportedOutputCapability(cameraDevice); let previewProfiles cameraOutputCapability.previewProfiles; // 创建预览输出流 let previewOutput cameraManager.createPreviewOutput(previewProfiles[0], surfaceId); })4. 会话管理与启动预览相机的输入流和输出流必须通过Session进行绑定和调度// 创建拍照模式的会话 let photoSession cameraManager.createSession(camera.SceneMode.NORMAL_PHOTO) as camera.PhotoSession; // 配置会话 photoSession.beginConfig(); photoSession.addInput(cameraInput); photoSession.addOutput(previewOutput); await photoSession.commitConfig(); // 启动会话此时 XComponent 上即可看到实时预览画面 await photoSession.start();三、 进阶拍照输出与模式切换当需要在预览的基础上实现拍照功能时需在会话中额外添加PhotoOutput// 创建拍照输出流 let photoOutput cameraManager.createPhotoOutput(); // 在会话中添加拍照输出流需先判断是否支持添加 if (photoSession.canAddOutput(photoOutput)) { photoSession.addOutput(photoOutput); } await photoSession.commitConfig(); // 调用拍照 photoOutput.capture();如果需要从“拍照模式”切换到“录像模式”可以通过stop()停止当前会话移除photoOutput添加videoOutput后重新commitConfig()并start()。1、 高级参数控制闪光灯、对焦与变焦在会话处于prepared或运行状态下开发者可以动态调整相机的各项参数闪光灯控制通过photoSession.hasFlash()判断设备是否支持闪光灯若支持可调用setFlashMode()设置自动、开启或关闭模式。对焦模式通过isFocusModeSupported()检查是否支持连续自动对焦FOCUS_MODE_CONTINUOUS_AUTO若支持则调用setFocusMode()启用。平滑变焦通过getZoomRatioRange()获取设备支持的可变焦距比范围然后调用setZoomRatio()设置具体的缩放比例。注意传入的缩放值必须在支持范围内否则系统会直接报错。2、 折叠屏设备的深度适配在折叠屏设备上随着设备的展开或折叠可用的摄像头可能会发生变化例如前置镜头被折入内部。开启自动切换通过isAutoDeviceSwitchSupported()检查设备是否支持自动切换镜头能力。若支持调用enableAutoDeviceSwitch(true)。系统会自动完成镜头切换、会话配置和参数接续避免黑屏。监听能力变更当系统自动切换镜头时由于不同镜头的变焦范围可能不一致系统会通过on(autoDeviceSwitchStatusChange)回调通知应用。应用需根据isDeviceCapabilityChanged字段重新获取变焦范围并更新 UI。UI 布局适配除了镜头切换还需监听折叠状态变化foldStatusChange并配合orientation: follow_desktop动态调整相机的 UI 布局。3、 严格的资源释放与生命周期管理相机是极其消耗系统资源的硬件。如果释放不当极易导致内存泄漏或下次打开相机时黑屏。安全释放顺序必须严格按照stop()-output.release()-cameraInput.close()-session.release()的顺序进行且每一步都必须包裹在try/catch中确保即使某一步报错也不会中断后续的释放流程。后台释放机制当应用退至后台时应立即释放相机资源当应用回到前台时再重新创建和启动会话。可通过监听applicationContext.on(applicationStateChange)来实现这一机制。模式切换恢复每次切换拍照或录像模式即创建新 Session后所有的参数设置都会回到默认值。必须在模式切换后主动调用类似syncButtonSettings()的逻辑将用户的自定义设置重新应用到新会话中。4、 高级拍照特性与底层细节处理HDR 与颜色空间若需拍摄高动态范围照片需在commitConfig()之前调用session.setColorSpace()设置合适的颜色空间如DISPLAY_P3或BT2020_HLG_LIMIT。动图Moving Photo支持实现类似 Live Photo 的动图功能需满足三个条件调用isMovingPhotoSupported()确认支持、调用enableMovingPhoto(true)开启、并在photoAssetAvailable回调中处理生成的资源。图像 Stride 对齐处理在进行底层图像数据处理如 AI 识别时需注意image.Component.rowStride可能大于图像的实际width。如果不进行裁剪对齐处理解析出的图像会出现竖条纹。四、 架构分层MVVM 模式下的相机模块设计在大型应用中直接在 UI 组件中处理复杂的相机逻辑会导致代码臃肿且难以维护。建议引入 MVVM 模式进行分层解耦View 层UI 组件XComponent组件仅负责渲染相机预览画面不包含任何业务逻辑。它通过Link或Prop接收来自 ViewModel 的状态如预览分辨率、闪光灯状态并通过事件回调通知 ViewModel 用户的交互如点击拍照、切换摄像头。ViewModel 层状态与逻辑作为相机模块的核心管理者ViewModel 持有CameraManager、PhotoSession等核心对象。它处理所有业务逻辑如权限校验、设备切换、参数调整、模式切换等并更新状态以驱动 UI 变化。Model 层数据源定义相机模块的数据结构和配置如支持的分辨率列表、闪光灯模式等可以来自本地配置或远程接口实现相机模块的动态化配置。五、 性能优化渲染与交互体验相机应用对性能要求极高任何卡顿都会严重影响用户体验。XComponent 渲染优化XComponent的宽高比必须与预览输出的分辨率保持一致否则会导致画面拉伸或黑边。建议在onLoad回调中动态计算并设置XComponent的尺寸确保预览画面完美填充。异步操作与线程管理相机的初始化、参数设置、拍照等操作都是耗时的。必须在异步线程中执行这些操作避免阻塞主线程。可以使用TaskPool或Worker来处理复杂的图像处理任务确保 UI 的流畅性。内存管理相机预览和拍照会产生大量的图像数据。必须及时释放不再使用的Image对象避免内存泄漏。在处理图像数据时建议使用ArrayBuffer的零拷贝特性减少内存分配和拷贝的开销。六、 生命周期管理严格的资源释放与状态恢复相机是极其消耗系统资源的硬件。如果管理不当极易导致内存泄漏或下次打开相机时黑屏。安全释放顺序必须严格按照session.stop()-output.release()-cameraInput.close()-session.release()的顺序进行且每一步都必须包裹在try/catch中确保即使某一步报错也不会中断后续的释放流程。后台释放机制当应用退至后台时应立即释放相机资源当应用回到前台时再重新创建和启动会话。可通过监听applicationContext.on(applicationStateChange)来实现这一机制。模式切换恢复每次切换拍照或录像模式即创建新 Session后所有的参数设置都会回到默认值。必须在模式切换后主动调用类似syncButtonSettings()的逻辑将用户的自定义设置重新应用到新会话中。

本月热点