相机能力:手动对焦、曝光与连拍模式(196)

相机能力:手动对焦、曝光与连拍模式(196) 在鸿蒙HarmonyOS应用开发中Camera Kit 提供了从基础自动模式到专业级手动控制的完整接口。在最新的 HarmonyOS 6.1.1 (API 24) 中系统更是全面开放了底层“原子级”的操控能力让开发者能够轻松实现专业级的相机应用。一、 手动对焦Manual Focus系统支持自动对焦AUTO_FRAMING、手动对焦等多种模式。在手动对焦模式下开发者可以精确控制镜头的对焦距离。对焦距离控制通过ManualFocus接口可以获取当前对焦距离并设置新的对焦距离。对焦距离的取值范围通常为[0.0, 1.0]其中0.0表示镜头可以对焦的最短距离1.0表示最远距离。对焦模式切换通过FocusMode枚举可以将相机切换至FOCUS_MODE_MANUAL手动对焦、FOCUS_MODE_AUTO自动对焦或FOCUS_MODE_CONTINUOUS_AUTO连续自动对焦等模式。// ManualFocusDemo.ets import { camera } from kit.CameraKit; import { BusinessError } from kit.BasicServicesKit; export class FocusController { private photoSession: camera.PhotoSession | null null; constructor(session: camera.PhotoSession) { this.photoSession session; } // 1. 切换至手动对焦模式并设置距离 public setManualFocus(distance: number) { if (!this.photoSession) return; try { // 检查设备是否支持手动对焦 if (this.photoSession.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_MANUAL)) { this.photoSession.setFocusMode(camera.FocusMode.FOCUS_MODE_MANUAL); // 设置对焦距离范围 [0.0, 1.0] this.photoSession.setFocusDistance(distance); } } catch (error) { console.error(设置手动对焦失败:, (error as BusinessError).code); } } // 2. 恢复连续自动对焦 public setContinuousAutoFocus() { if (!this.photoSession) return; try { if (this.photoSession.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO)) { this.photoSession.setFocusMode(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO); } } catch (error) { console.error(设置连续自动对焦失败:, (error as BusinessError).code); } } }二、 曝光与测光控制Exposure Metering摄影本质上是光影的艺术。系统支持对曝光模式和测光模式进行精细化调节。手动曝光时长在EXPOSURE_MODE_MANUAL模式下开发者可以通过ManualExposure接口精准设置微秒级μs的曝光时长快门开合时间并获取设备支持的曝光时长范围。测光模式切换通过PhotoSession的setExposureMeteringMode接口可以指定画面的测光权重模式如矩阵测光MATRIX、中央重点测光CENTER或点测光SPOT。ISO与光圈控制针对极致性能需求底层的 C API 还支持锁定 ISO 感光度以及调整物理光圈大小为机器视觉和专业相机提供原生支持。// ExposureController.ets import { camera } from kit.CameraKit; import { BusinessError } from kit.BasicServicesKit; export class ExposureController { private photoSession: camera.PhotoSession | null null; constructor(session: camera.PhotoSession) { this.photoSession session; } // 1. 切换测光模式 public setMeteringMode(mode: camera.ExposureMeteringMode) { try { this.photoSession?.setExposureMeteringMode(mode); } catch (error) { console.error(设置测光模式失败:, (error as BusinessError).code); } } // 2. 锁定曝光并手动设置 ISO public setManualIso(iso: number) { if (!this.photoSession) return; try { // 核心避坑必须先锁定曝光模式否则 setIso 会报错 this.photoSession.setExposureMode(camera.ExposureMode.EXPOSURE_MODE_LOCKED); // 获取支持的 ISO 档位并设置 const supportedIso this.photoSession.getSupportedIsoRange(); if (supportedIso.includes(iso)) { this.photoSession.setIso(iso); } } catch (error) { console.error(设置 ISO 失败:, (error as BusinessError).code); } } // 3. 设置手动曝光时长微秒 public setManualExposureDuration(duration: number) { try { this.photoSession?.setExposureMode(camera.ExposureMode.EXPOSURE_MODE_MANUAL); this.photoSession?.setExposureDuration(duration); } catch (error) { console.error(设置曝光时长失败:, (error as BusinessError).code); } } }三、 连拍模式Burst Mode连拍功能允许用户连续捕捉运动过程从中挑选最精彩的瞬间。触发机制在应用层连拍通常通过监听快门按键的“长按”事件来触发。用户长按快门时启动连续拍照抬起手指时停止。状态反馈在连拍过程中UI 层可以实时接收并展示当前已拍摄的照片数量为用户提供直观的视觉反馈。后期筛选连拍生成的照片组在保存至图库后用户可以在相册中进入该组照片勾选想要保留的精选照片并支持一键删除整组连拍照片。// BurstCaptureDemo.ets import { camera } from kit.CameraKit; import { BusinessError } from kit.BasicServicesKit; Entry Component struct BurstCaptureDemo { State burstCount: number 0; private photoOutput: camera.PhotoOutput | null null; private isBursting: boolean false; // 1. 启动连拍 private startBurstCapture() { if (this.isBursting || !this.photoOutput) return; this.isBursting true; this.burstCount 0; // 监听拍照准备就绪事件实现高速连续 capture this.photoOutput.on(captureReady, () { if (this.isBursting) { this.photoOutput?.capture(); this.burstCount; } }); // 触发第一次拍照 this.photoOutput.capture(); } // 2. 停止连拍 private stopBurstCapture() { this.isBursting false; this.photoOutput?.off(captureReady); console.info(连拍结束共拍摄 ${this.burstCount} 张); } build() { Column() { Text(已拍摄: ${this.burstCount} 张) .fontSize(24) .margin({ bottom: 20 }) Button(长按连拍) .onTouch((event) { if (event.type TouchType.Down) { this.startBurstCapture(); } else if (event.type TouchType.Up) { this.stopBurstCapture(); } }) } .width(100%) .height(100%) .justifyContent(FlexAlign.Center) } }四、 相机能力实战手动对焦与曝光参数调节在开发专业级相机应用时精确控制镜头的对焦与曝光参数是核心需求。手动对焦距离设置通过CameraAbility类提供的setFocusMode方法将模式调整为FocusMode.MANUAL后即可调用setFocusDistance(float distance)方法精确设置对焦距离。距离值通常在0.0无限远到1.0最近对焦之间。在设置前建议通过getSupportedFocusDistances()查询设备支持的具体范围以适配不同硬件。手动曝光与ISO控制在 ArkTS 层ISO 控制能力挂载在 Session捕获会话继承体系中。首先需通过getSupportedIsoRange()获取当前设备支持的离散 ISO 标准值数组number[]。当曝光模式非 LOCKED 时需先将其设置为EXPOSURE_MODE_LOCKED随后即可选择标准 ISO 档位并调用setIso进行感光度设置。此外也可通过CaptureRequest传入自定义的 4×5 矩阵或参数键如CaptureParameter.ISO、CaptureParameter.EXPOSURE_TIME来实现对感光度和快门时间的精细调节。// ProCameraControls.ets import { camera } from kit.CameraKit; export class ProCameraControls { private session: camera.PhotoSession | null null; constructor(session: camera.PhotoSession) { this.session session; } // 1. 手动对焦距离设置 public setManualFocus(distance: number) { if (!this.session) return; try { // 前置校验检查是否支持手动对焦 if (this.session.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_MANUAL)) { this.session.setFocusMode(camera.FocusMode.FOCUS_MODE_MANUAL); // 限制范围在 [0.0, 1.0] 之间 const safeDistance Math.max(0, Math.min(1, distance)); this.session.setFocusDistance(safeDistance); } } catch (err) { console.error(手动对焦设置失败:, err); } } // 2. 手动 ISO 控制 public setManualIso(targetIso: number) { if (!this.session) return; try { // 核心必须先锁定曝光模式 this.session.setExposureMode(camera.ExposureMode.EXPOSURE_MODE_LOCKED); // 获取支持的离散 ISO 档位 const supportedIsos this.session.getSupportedIsoRange(); // 找到最接近目标值的合法 ISO const validIso supportedIsos.reduce((prev, curr) Math.abs(curr - targetIso) Math.abs(prev - targetIso) ? curr : prev ); this.session.setIso(validIso); } catch (err) { console.error(ISO 设置失败:, err); } } }五、 连拍模式与状态反馈机制连拍功能需要应用层与底层硬件的高效配合以确保在极短时间内连续捕获高质量图像。长按触发与状态同步在 UI 层通常通过监听快门按钮的长按手势如LongPressGesture来触发连拍。按下时启动连续拍照任务抬起时立即停止。底层连拍与HDR堆栈处理在底层可利用 Camera Kit 提供的captureBurst接口实现高速连拍。该接口支持传入连拍帧数frames以及曝光包围exposureBracketing参数例如连续拍摄 5 帧并应用[-2, 0, 2]的曝光补偿随后可通过回调函数如.then(mergeHDR)进行 HDR 堆栈合并处理大幅提升动态范围。实时进度反馈在连拍过程中应用需通过状态变量实时记录并展示当前已拍摄的照片数量为用户提供直观的视觉反馈。连拍结束后生成的照片组可支持在相册中进行二次筛选与批量管理。// BurstCaptureUI.ets import { camera } from kit.CameraKit; Entry Component struct BurstCaptureUI { State burstCount: number 0; State isBursting: boolean false; private photoOutput: camera.PhotoOutput | null null; // 1. 长按触发连拍 private handleShutterPress(isDown: boolean) { if (isDown !this.isBursting) { this.isBursting true; this.burstCount 0; this.startContinuousCapture(); } else if (!isDown this.isBursting) { this.isBursting false; console.info(连拍结束共拍摄 ${this.burstCount} 张); } } // 2. 循环调用 capture 实现连拍 private async startContinuousCapture() { while (this.isBursting this.photoOutput) { try { await this.photoOutput.capture(); this.burstCount; // 实时状态反馈 } catch (err) { break; // 遇到异常或停止指令则退出 } } } build() { Button(长按连拍) .onTouch((event) { if (event.type TouchType.Down) this.handleShutterPress(true); if (event.type TouchType.Up) this.handleShutterPress(false); }) } }六、 性能优化与异常处理相机操作极易受设备状态影响稳健的错误处理与资源管理是保证应用不崩溃的关键。参数配置的前置校验在设置任何对焦或曝光模式前必须先调用类似isFocusModeSupported的接口检查设备是否支持该模式。此外所有的参数设置必须在 Session 调用commitConfig完成配流之后进行否则会导致配置失效或报错。异步执行与资源释放AI 场景识别、HDR 合并等图像处理操作可能会增加延迟建议在后台线程如 TaskPool中运行避免阻塞预览帧率。同时必须妥善处理权限拒绝、相机被占用CAMERA_IN_USE或系统资源不足INSUFFICIENT_RESOURCES等异常并在应用退出或页面销毁时及时释放未使用的输出表面releaseUnusedOutputs防止内存泄漏。// CameraSafetyManager.ets import { camera } from kit.CameraKit; import { taskpool } from kit.ArkTS; export class CameraSafetyManager { // 1. 参数配置的前置校验 public static safeSetFocusMode(session: camera.PhotoSession, mode: camera.FocusMode) { // 必须在 commitConfig 之后且设备支持该模式 if (session.isFocusModeSupported(mode)) { session.setFocusMode(mode); } else { console.warn(当前设备不支持对焦模式: ${mode}); } } // 2. 异步执行耗时操作如 HDR 合并防阻塞 Concurrent async function mergeHDRStack(frames: ArrayBuffer[]): PromiseArrayBuffer { // 在 TaskPool 中执行耗时的 HDR 堆栈合并算法 // ... 核心合并逻辑 return mergedResult; } // 3. 页面销毁时的安全释放 public static async safeRelease(photoSession: camera.PhotoSession) { try { // 释放未使用的输出表面防止内存泄漏 photoSession.releaseUnusedOutputs(); await photoSession.stop(); } catch (err) { console.error(相机资源释放异常:, err); } } }