当前位置: 首页 > news >正文

相机开发: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): Promise<picker.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或运行状态下,开发者可以动态调整相机的各项参数:

  1. 闪光灯控制:通过photoSession.hasFlash()判断设备是否支持闪光灯,若支持,可调用setFlashMode()设置自动、开启或关闭模式。
  2. 对焦模式:通过isFocusModeSupported()检查是否支持连续自动对焦(FOCUS_MODE_CONTINUOUS_AUTO),若支持则调用setFocusMode()启用。
  3. 平滑变焦:通过getZoomRatioRange()获取设备支持的可变焦距比范围,然后调用setZoomRatio()设置具体的缩放比例。注意:传入的缩放值必须在支持范围内,否则系统会直接报错。
2、 折叠屏设备的深度适配

在折叠屏设备上,随着设备的展开或折叠,可用的摄像头可能会发生变化(例如前置镜头被折入内部)。

  1. 开启自动切换:通过isAutoDeviceSwitchSupported()检查设备是否支持自动切换镜头能力。若支持,调用enableAutoDeviceSwitch(true)。系统会自动完成镜头切换、会话配置和参数接续,避免黑屏。
  2. 监听能力变更:当系统自动切换镜头时,由于不同镜头的变焦范围可能不一致,系统会通过on('autoDeviceSwitchStatusChange')回调通知应用。应用需根据isDeviceCapabilityChanged字段重新获取变焦范围并更新 UI。
  3. UI 布局适配:除了镜头切换,还需监听折叠状态变化(foldStatusChange),并配合orientation: follow_desktop动态调整相机的 UI 布局。
3、 严格的资源释放与生命周期管理

相机是极其消耗系统资源的硬件。如果释放不当,极易导致内存泄漏或下次打开相机时黑屏。

  1. 安全释放顺序:必须严格按照stop()->output.release()->cameraInput.close()->session.release()的顺序进行,且每一步都必须包裹在try/catch中,确保即使某一步报错也不会中断后续的释放流程。
  2. 后台释放机制:当应用退至后台时,应立即释放相机资源;当应用回到前台时,再重新创建和启动会话。可通过监听applicationContext.on('applicationStateChange')来实现这一机制。
  3. 模式切换恢复:每次切换拍照或录像模式(即创建新 Session)后,所有的参数设置都会回到默认值。必须在模式切换后主动调用类似syncButtonSettings()的逻辑,将用户的自定义设置重新应用到新会话中。
4、 高级拍照特性与底层细节处理
  1. HDR 与颜色空间:若需拍摄高动态范围照片,需在commitConfig()之前调用session.setColorSpace()设置合适的颜色空间(如DISPLAY_P3BT2020_HLG_LIMIT)。
  2. 动图(Moving Photo)支持:实现类似 Live Photo 的动图功能需满足三个条件:调用isMovingPhotoSupported()确认支持、调用enableMovingPhoto(true)开启、并在photoAssetAvailable回调中处理生成的资源。
  3. 图像 Stride 对齐处理:在进行底层图像数据处理(如 AI 识别)时,需注意image.Component.rowStride可能大于图像的实际width。如果不进行裁剪对齐处理,解析出的图像会出现竖条纹。

四、 架构分层:MVVM 模式下的相机模块设计

在大型应用中,直接在 UI 组件中处理复杂的相机逻辑会导致代码臃肿且难以维护。建议引入 MVVM 模式进行分层解耦:

  1. View 层(UI 组件)XComponent组件仅负责渲染相机预览画面,不包含任何业务逻辑。它通过@Link@Prop接收来自 ViewModel 的状态(如预览分辨率、闪光灯状态),并通过事件回调通知 ViewModel 用户的交互(如点击拍照、切换摄像头)。
  2. ViewModel 层(状态与逻辑):作为相机模块的核心管理者,ViewModel 持有CameraManagerPhotoSession等核心对象。它处理所有业务逻辑,如权限校验、设备切换、参数调整、模式切换等,并更新状态以驱动 UI 变化。
  3. Model 层(数据源):定义相机模块的数据结构和配置,如支持的分辨率列表、闪光灯模式等,可以来自本地配置或远程接口,实现相机模块的动态化配置。

五、 性能优化:渲染与交互体验

相机应用对性能要求极高,任何卡顿都会严重影响用户体验。

  1. XComponent 渲染优化XComponent的宽高比必须与预览输出的分辨率保持一致,否则会导致画面拉伸或黑边。建议在onLoad回调中动态计算并设置XComponent的尺寸,确保预览画面完美填充。
  2. 异步操作与线程管理:相机的初始化、参数设置、拍照等操作都是耗时的。必须在异步线程中执行这些操作,避免阻塞主线程。可以使用TaskPoolWorker来处理复杂的图像处理任务,确保 UI 的流畅性。
  3. 内存管理:相机预览和拍照会产生大量的图像数据。必须及时释放不再使用的Image对象,避免内存泄漏。在处理图像数据时,建议使用ArrayBuffer的零拷贝特性,减少内存分配和拷贝的开销。

六、 生命周期管理:严格的资源释放与状态恢复

相机是极其消耗系统资源的硬件。如果管理不当,极易导致内存泄漏或下次打开相机时黑屏。

  1. 安全释放顺序:必须严格按照session.stop()->output.release()->cameraInput.close()->session.release()的顺序进行,且每一步都必须包裹在try/catch中,确保即使某一步报错也不会中断后续的释放流程。
  2. 后台释放机制:当应用退至后台时,应立即释放相机资源;当应用回到前台时,再重新创建和启动会话。可通过监听applicationContext.on('applicationStateChange')来实现这一机制。
  3. 模式切换恢复:每次切换拍照或录像模式(即创建新 Session)后,所有的参数设置都会回到默认值。必须在模式切换后主动调用类似syncButtonSettings()的逻辑,将用户的自定义设置重新应用到新会话中。
http://www.jsqmd.com/news/1256942/

相关文章:

  • AI-Salesman: Towards Reliable Large Language Model Driven Telemarketing
  • 【2019-02-22】linux下so动态库裁剪
  • 宁波美妆个护行业GEO服务商代理加盟选型哪家靠谱?2026年宁波GEO代理服务商本地推荐 - 子柔传媒
  • 2026平湖黄金回收实报实收|所见即所得,没有隐形扣费的商家推荐 - 微城市网络
  • 国补2026补贴以旧换新最新消息,国补领取入口和操作流程,7月京东国补家电空调电器补贴,国补教育优惠怎么叠加,京东淘宝红包怎么领取 - 优企甄选
  • Topit:终极Mac窗口置顶工具完整指南 - 高效多任务工作新体验
  • 3步完成Switch大气层系统安装:从新手到高手的实用指南
  • Seedance2.0深度解析:从动漫爽剧到商业大片的AI影视转型之道
  • 2026年宁波GEO服务商代理加盟选型推荐丨宁波自动化解决方案领域GEO代理服务商哪家靠谱? - 企业新闻快传
  • 2026 年新消息:滨湖品质可靠的双玻百叶隔断施工公司怎么联系,办公室里这款常用隔断,竟藏着你不知道的省钱小技巧,解决70%的办公空间痛点 - 行业推荐官【认证】
  • 国际首都公报:放飞炬人集团行政总裁方达炬批准《集团国际财务责任001001支柱上项目产品的制成、上市、经济司法制度的应税价格》
  • 剪贴板管理:系统剪贴板的读写与数据格式处理(39)
  • 泸州本地整装装饰公司靠谱推荐,分阶段验收付款 + 24 小时售后维保 附家庭装修预算合理规划指南 - 资讯速览
  • 【Bug已解决】Proposal: add MiCA (Minor Component Adaptation) as a new PEFT method 解决方案
  • OpenClaw配置加密实战:保护API密钥与敏感信息的安全方案
  • 3分钟掌握QMK Toolbox:让键盘固件刷写变得像点鼠标一样简单
  • 终极突破:5大技术解密Adobe GenP二进制激活引擎实现原理
  • 打造健康办公环境哪家强?2026年智慧办公环境服务商实力TOP5测评
  • 30天总结--,第八天
  • 可以生成 word 的 ChatGPT,导出排版错乱格式变形问题频发,AI 导出鸭适配 GPT 内容一键规整输出标准 Word 文件
  • 2026中英双语授课的国内EMBA中立择校测评
  • 【湿法-萃取工艺20】---MSP废水处-四大核心技术深度细化
  • 医疗人工智能的Harness Engineering:面向安全、可控与合规的大模型系统工程(六)
  • 成都专科院校择校指南:聚焦项目实训与城市资源整合 - 行业洞察分析师
  • cppm报名网站 - 众智商学院职业教育
  • Steam创意工坊模组下载终极指南:如何免费获取1000+游戏模组
  • C++题目迷宫(1~8)详解
  • 猫抓Cat-Catch:专业网页视频资源嗅探工具完整使用指南
  • 佳能喷墨机打印机提示1700,1701,1702,5B00,5B02 5B04,P07,E08这些报错只需清零即可,常见型号ts3380,mg3660,g3800,g4810,ts9120亲测完美。
  • 【安心陪诊 Agent】Node.js 20 + Express 4 实战:陪诊市场假设与任务链契约测试