自己开发的HarmonyOS App拍照会是怎样
一、小知识
你有没有遇到过这样的尴尬——用自己开发的 App 拍照,结果照片糊得像打了马赛克?或者晚上拍照一片漆黑,闪光灯死活不亮?又或者想拍一组连拍,结果只能一张一张按?
拍照,看似只是"按下快门"这一个动作,但背后涉及的东西远比你想象的多。PhotoSession 是拍照的核心会话,它管理着从预览到成片的整条数据流。闪光灯的控制不是简单的开关,而是要根据环境光智能判断。定时拍照需要精确的倒计时管理和 UI 反馈。连拍模式则要处理高速图像采集和存储的性能问题。
这篇文章,我们就把拍照这件事掰开揉碎了讲清楚。
二、核心原理
2.1 PhotoSession 数据流架构
PhotoSession 是拍照场景的会话管理器,它将相机输入、预览输出和拍照输出串联起来,形成一条完整的数据流:
flowchart LR
classDef primary fill:#4A90D9,stroke:#2C5F8A,color:#fff,font-weight:bold
classDef warning fill:#E8A838,stroke:#B87A1A,color:#fff,font-weight:bold
classDef error fill:#D94A4A,stroke:#8A2C2C,color:#fff,font-weight:bold
classDef info fill:#50B5A9,stroke:#2C7A6F,color:#fff,font-weight:bold
classDef purple fill:#9B59B6,stroke:#6C3483,color:#fff,font-weight:bold
A[CameraInput<br/>相机输入]:::primary --> B[PhotoSession<br/>拍照会话]:::error
B --> C[PreviewOutput<br/>预览输出]:::info
B --> D[PhotoOutput<br/>拍照输出]:::warning
D --> E[相册/文件系统]:::purple
F[闪光灯控制]:::warning -.-> B
G[对焦模式]:::info -.-> B
H[曝光补偿]:::purple -.-> B
style B stroke-width:4px
关键流程:
- 创建会话:
cameraManager.createPhotoSession(cameraInput, previewOutput, photoOutput) - 配置参数:设置闪光灯、对焦、曝光等
- 启动会话:
session.start()开始预览 - 触发拍照:
photoOutput.capture()捕获图像 - 接收结果:通过回调获取拍照完成的通知
2.2 拍照完整流程
flowchart TD
classDef primary fill:#4A90D9,stroke:#2C5F8A,color:#fff,font-weight:bold
classDef warning fill:#E8A838,stroke:#B87A1A,color:#fff,font-weight:bold
classDef error fill:#D94A4A,stroke:#8A2C2C,color:#fff,font-weight:bold
classDef info fill:#50B5A9,stroke:#2C7A6F,color:#fff,font-weight:bold
classDef purple fill:#9B59B6,stroke:#6C3483,color:#fff,font-weight:bold
A[创建PhotoOutput]:::primary --> B[创建PhotoSession]:::primary
B --> C[配置会话参数]:::info
C --> D[session.start]:::warning
D --> E{用户操作}:::purple
E -->|单拍| F[photoOutput.capture]:::error
E -->|连拍| G[循环调用capture]:::error
E -->|定时拍| H[倒计时后capture]:::error
F --> I[拍照回调]:::info
G --> I
H --> I
I --> J[保存图片]:::purple
style E stroke-width:3px
style F stroke-width:3px
2.3 闪光灯模式
闪光灯有三种模式,理解它们的区别很重要:
| 模式 | 说明 | 适用场景 |
|---|---|---|
| FLASH_MODE_CLOSE | 始终关闭 | 拍风景、拍文档 |
| FLASH_MODE_OPEN | 始终开启 | 暗光环境补光 |
| FLASH_MODE_AUTO | 自动判断 | 日常拍摄(推荐默认值) |
| FLASH_MODE_ALWAYS_ON | 常亮(手电筒) | 录像补光 |
2.4 连拍模式原理
连拍的核心是快速连续调用 capture() 方法,系统会在底层做帧缓冲,确保高速采集不会丢帧。但要注意:
- 连拍速度受硬件限制,通常 3-10 张/秒
- 连拍时内存占用会快速上升,需要及时处理回调释放缓冲
- 连拍数量要有上限,否则可能 OOM
三、代码实战
3.1 PhotoSession 基础拍照
这是最基础的拍照实现——创建会话、启动预览、按下快门、保存照片。
import { camera } from '@kit.CameraKit';
import { image } from '@kit.ImageKit';
import { fileIo as fs } from '@kit.CoreFileKit';
import { BusinessError } from '@kit.BasicServicesKit';
/**
* 基础拍照控制器
* 实现完整的拍照流程:创建会话 → 预览 → 拍照 → 保存
*/
export class PhotoCaptureController {
private cameraManager: camera.CameraManager | null = null;
private cameraInput: camera.CameraInput | null = null;
private photoSession: camera.PhotoSession | null = null;
private previewOutput: camera.PreviewOutput | null = null;
private photoOutput: camera.PhotoOutput | null = null;
// 拍照结果回调
private onPhotoTaken?: (uri: string) => void;
private onError?: (error: BusinessError) => void;
/**
* 初始化拍照会话
* @param context 应用上下文
* @param surfaceId 预览的 Surface ID
*/
async init(context: Context, surfaceId: string): Promise<boolean> {
try {
// 1. 创建 CameraManager
this.cameraManager = camera.getCameraManager(context);
// 2. 获取后置摄像头
const devices = this.cameraManager.getSupportedCameras();
const backCamera = devices.find(
d => d.cameraPosition === camera.CameraPosition.CAMERA_POSITION_BACK
) || devices[0];
// 3. 创建 CameraInput 并打开
this.cameraInput = this.cameraManager.createCameraInput(backCamera);
await this.cameraInput.open();
// 4. 获取输出能力
const capability = this.cameraManager.getSupportedOutputCapability(backCamera);
// 5. 创建预览输出
const previewProfile = capability.previewProfiles[0];
this.previewOutput = this.cameraManager.createPreviewOutput(previewProfile, surfaceId);
// 6. 创建拍照输出
const photoProfile = capability.photoProfiles[0];
this.photoOutput = this.cameraManager.createPhotoOutput(photoProfile);
// 7. 创建 PhotoSession
this.photoSession = this.cameraManager.createPhotoSession(
this.cameraInput,
this.previewOutput,
this.photoOutput
);
// 8. 注册拍照回调
this.setupPhotoCallback();
// 9. 启动会话
await this.photoSession.start();
console.info('[拍照] 初始化完成,会话已启动');
return true;
} catch (error) {
const err = error as BusinessError;
console.error(`[拍照初始化失败] code: ${err.code}, msg: ${err.message}`);
this.onError?.(err);
return false;
}
}
/**
* 注册拍照输出回调
* 这是接收拍照结果的核心机制
*/
private setupPhotoCallback(): void {
if (!this.photoOutput) return;
// 拍照完成回调 - 照片可用时触发
this.photoOutput.on('photoAvailable', (photo: camera.Photo): void => {
console.info('[拍照] 照片已捕获,开始处理');
// 获取照片的主图像
const mainImage = photo.main;
if (mainImage) {
this.savePhoto(mainImage);
}
});
// 拍照开始回调 - 快门按下时触发
this.photoOutput.on('captureStart', (captureInfo: camera.CaptureStartInfo): void => {
console.info(`[拍照] 快门已按下, captureId: ${captureInfo.captureId}`);
});
// 拍照结束回调 - 图像处理完成时触发
this.photoOutput.on('captureEnd', (endInfo: camera.CaptureEndInfo): void => {
console.info(`[拍照] 图像处理完成, captureId: ${endInfo.captureId}, frameCount: ${endInfo.frameCount}`);
});
// 拍照错误回调
this.photoOutput.on('error', (errorInfo: BusinessError): void => {
console.error(`[拍照错误] code: ${errorInfo.code}, msg: ${errorInfo.message}`);
});
}
/**
* 保存照片到本地
* @param photo 图片数据
*/
private async savePhoto(photo: image.Image): Promise<void> {
try {
// 创建图片打包器
const imagePackerApi = image.createImagePacker();
// 打包参数
const packOpts: image.PackingOption = {
format: 'image/jpeg',
quality: 95
};
// 将图片打包为 ArrayBuffer
const data = await imagePackerApi.packing(photo, packOpts);
// 生成文件路径
const fileName = `IMG_${Date.now()}.jpg`;
const filePath = `${getContext().filesDir}/${fileName}`;
// 写入文件
const file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
fs.writeSync(file.fd, data);
fs.closeSync(file);
console.info(`[拍照] 照片已保存: ${filePath}`);
this.onPhotoTaken?.(filePath);
// 释放资源
imagePackerApi.release();
photo.release();
} catch (error) {
console.error(`[照片保存失败] ${error}`);
}
}
/**
* 执行拍照
* 这是对外暴露的核心方法
*/
async capture(): Promise<void> {
if (!this.photoOutput) {
console.error('[拍照] PhotoOutput 未初始化');
return;
}
try {
// 拍照配置
const captureSetting: camera.PhotoCaptureSetting = {
quality: camera.QualityLevel.QUALITY_LEVEL_HIGH, // 高质量
rotation: camera.ImageRotation.ROTATION_0, // 不旋转
mirror: false, // 不镜像
};
// 触发拍照
await this.photoOutput.capture(captureSetting);
console.info('[拍照] capture 已触发');
} catch (error) {
const err = error as BusinessError;
console.error(`[拍照失败] code: ${err.code}, msg: ${err.message}`);
}
}
/**
* 释放所有资源
*/
async release(): Promise<void> {
try {
if (this.photoSession) {
await this.photoSession.stop();
await this.photoSession.release();
}
if (this.previewOutput) {
await this.previewOutput.release();
}
if (this.photoOutput) {
await this.photoOutput.release();
}
if (this.cameraInput) {
await this.cameraInput.close();
await this.cameraInput.release();
}
console.info('[拍照] 资源已全部释放');
} catch (error) {
console.error(`[资源释放失败] ${error}`);
}
}
}
3.2 闪光灯控制
闪光灯不是简单的开关,它有自动模式,需要根据当前环境光条件智能判断。这个示例实现了完整的闪光灯控制逻辑。
import { camera } from '@kit.CameraKit';
import { BusinessError } from '@kit.BasicServicesKit';
/**
* 闪光灯控制器
* 支持关闭/开启/自动/常亮四种模式
*/
export class FlashController {
private photoSession: camera.PhotoSession | null = null;
// 当前闪光灯模式
@State currentMode: camera.FlashMode = camera.FlashMode.FLASH_MODE_CLOSE;
/**
* 绑定 PhotoSession
* 闪光灯控制依赖于会话对象
*/
bindSession(session: camera.PhotoSession): void {
this.photoSession = session;
// 初始化为自动模式
this.setFlashMode(camera.FlashMode.FLASH_MODE_AUTO);
}
/**
* 设置闪光灯模式
* @param mode 目标模式
*/
setFlashMode(mode: camera.FlashMode): boolean {
if (!this.photoSession) {
console.error('[闪光灯] 会话未绑定');
return false;
}
try {
// 先检查设备是否支持该模式
const supportedModes = this.photoSession.getSupportedFlashModes();
if (!supportedModes.includes(mode)) {
console.warn(`[闪光灯] 不支持模式: ${mode}`);
return false;
}
// 设置闪光灯模式
this.photoSession.setFlashMode(mode);
this.currentMode = mode;
const modeText = this.getFlashModeText(mode);
console.info(`[闪光灯] 已切换到: ${modeText}`);
return true;
} catch (error) {
const err = error as BusinessError;
console.error(`[闪光灯设置失败] code: ${err.code}, msg: ${err.message}`);
return false;
}
}
/**
* 切换到下一个闪光灯模式
* 依次循环:关闭 → 自动 → 开启 → 常亮 → 关闭
*/
cycleFlashMode(): camera.FlashMode {
if (!this.photoSession) return this.currentMode;
const supportedModes = this.photoSession.getSupportedFlashModes();
const currentIndex = supportedModes.indexOf(this.currentMode);
const nextIndex = (currentIndex + 1) % supportedModes.length;
const nextMode = supportedModes[nextIndex];
this.setFlashMode(nextMode);
return nextMode;
}
/**
* 判断当前是否支持闪光灯
*/
hasFlash(): boolean {
if (!this.photoSession) return false;
const modes = this.photoSession.getSupportedFlashModes();
// 如果只有关闭模式,说明设备没有闪光灯
return modes.length > 1;
}
/**
* 获取当前闪光灯模式文本
*/
getFlashModeText(mode: camera.FlashMode): string {
const map: Record<number, string> = {
[camera.FlashMode.FLASH_MODE_CLOSE]: '关闭',
[camera.FlashMode.FLASH_MODE_OPEN]: '开启',
[camera.FlashMode.FLASH_MODE_AUTO]: '自动',
[camera.FlashMode.FLASH_MODE_ALWAYS_ON]: '常亮',
};
return map[mode] || '未知';
}
/**
* 获取闪光灯图标标识
* 用于UI展示
*/
getFlashIcon(mode: camera.FlashMode): string {
const map: Record<number, string> = {
[camera.FlashMode.FLASH_MODE_CLOSE]: '⚡⊘', // 关闭
[camera.FlashMode.FLASH_MODE_OPEN]: '⚡', // 开启
[camera.FlashMode.FLASH_MODE_AUTO]: '⚡A', // 自动
[camera.FlashMode.FLASH_MODE_ALWAYS_ON]: '⚡🔒', // 常亮
};
return map[mode] || '⚡⊘';
}
}
3.3 定时拍照与连拍模式
这个示例实现了两种高级拍照模式:定时拍照(3秒/5秒/10秒倒计时)和连拍模式(可配置连拍张数和间隔)。
import { camera } from '@kit.CameraKit';
import { BusinessError } from '@kit.BasicServicesKit';
/**
* 高级拍照控制器
* 支持定时拍照和连拍模式
*/
export class AdvancedPhotoController {
private photoOutput: camera.PhotoOutput | null = null;
private photoSession: camera.PhotoSession | null = null;
// 定时拍照状态
private timerCountdown: number = 0;
private timerHandle: number = -1;
private onCountdownTick?: (remaining: number) => void;
private onCountdownFinish?: () => void;
// 连拍状态
private isBursting: boolean = false;
private burstCount: number = 0;
private burstMaxCount: number = 10;
private burstInterval: number = 200; // 毫秒
private onBurstProgress?: (current: number, total: number) => void;
/**
* 绑定拍照输出和会话
*/
bind(photoOutput: camera.PhotoOutput, session: camera.PhotoSession): void {
this.photoOutput = photoOutput;
this.photoSession = session;
}
/**
* 定时拍照
* @param delaySeconds 延迟秒数(3/5/10)
* @param onTick 每秒倒计时回调
* @param onFinish 倒计时结束回调
*/
async startTimerCapture(
delaySeconds: number,
onTick?: (remaining: number) => void,
onFinish?: () => void
): Promise<void> {
if (!this.photoOutput) {
console.error('[定时拍照] PhotoOutput 未初始化');
return;
}
this.onCountdownTick = onTick;
this.onCountdownFinish = onFinish;
this.timerCountdown = delaySeconds;
console.info(`[定时拍照] 开始倒计时: ${delaySeconds}秒`);
// 启动倒计时
this.timerHandle = setInterval(() => {
this.timerCountdown--;
this.onCountdownTick?.(this.timerCountdown);
if (this.timerCountdown <= 0) {
// 倒计时结束,清除定时器
clearInterval(this.timerHandle);
this.timerHandle = -1;
// 触发拍照
this.executeCapture();
this.onCountdownFinish?.();
}
}, 1000) as unknown as number;
// 立即触发第一次回调
this.onCountdownTick?.(this.timerCountdown);
}
/**
* 取消定时拍照
*/
cancelTimerCapture(): void {
if (this.timerHandle !== -1) {
clearInterval(this.timerHandle);
this.timerHandle = -1;
this.timerCountdown = 0;
console.info('[定时拍照] 已取消');
}
}
/**
* 连拍模式
* @param count 连拍张数
* @param interval 每张间隔(毫秒)
* @param onProgress 进度回调
*/
async startBurstCapture(
count: number = 10,
interval: number = 200,
onProgress?: (current: number, total: number) => void
): Promise<void> {
if (!this.photoOutput) {
console.error('[连拍] PhotoOutput 未初始化');
return;
}
if (this.isBursting) {
console.warn('[连拍] 正在连拍中,请勿重复触发');
return;
}
this.isBursting = true;
this.burstCount = 0;
this.burstMaxCount = count;
this.burstInterval = interval;
this.onBurstProgress = onProgress;
console.info(`[连拍] 开始: 共${count}张, 间隔${interval}ms`);
// 连拍循环
await this.burstLoop();
}
/**
* 连拍循环
* 递归调用实现定时连拍
*/
private async burstLoop(): Promise<void> {
if (!this.isBursting || this.burstCount >= this.burstMaxCount) {
// 连拍完成
this.isBursting = false;
console.info(`[连拍] 完成,共拍摄 ${this.burstCount} 张`);
return;
}
try {
// 执行单次拍照
await this.executeCapture();
this.burstCount++;
// 通知进度
this.onBurstProgress?.(this.burstCount, this.burstMaxCount);
// 延迟后继续下一张
setTimeout(() => {
this.burstLoop();
}, this.burstInterval);
} catch (error) {
console.error(`[连拍] 第${this.burstCount + 1}张拍摄失败: ${error}`);
this.isBursting = false;
}
}
/**
* 停止连拍
*/
stopBurstCapture(): void {
this.isBursting = false;
console.info(`[连拍] 已停止,已拍摄 ${this.burstCount} 张`);
}
/**
* 执行单次拍照
*/
private async executeCapture(): Promise<void> {
if (!this.photoOutput) return;
try {
const captureSetting: camera.PhotoCaptureSetting = {
quality: camera.QualityLevel.QUALITY_LEVEL_HIGH,
rotation: camera.ImageRotation.ROTATION_0,
mirror: false,
};
await this.photoOutput.capture(captureSetting);
} catch (error) {
const err = error as BusinessError;
console.error(`[拍照执行失败] code: ${err.code}, msg: ${err.message}`);
throw error;
}
}
/**
* 获取连拍状态
*/
getBurstingState(): { isBursting: boolean; count: number; maxCount: number } {
return {
isBursting: this.isBursting,
count: this.burstCount,
maxCount: this.burstMaxCount
};
}
}
/**
* UI 组件 - 拍照页面
* 集成定时拍照和连拍功能
*/
@Entry
@Component
struct PhotoPage {
private photoController: AdvancedPhotoController = new AdvancedPhotoController();
private flashController: FlashController = new FlashController();
@State countdown: number = 0; // 倒计时剩余秒数
@State isBursting: boolean = false; // 是否正在连拍
@State burstProgress: string = ''; // 连拍进度文本
@State flashModeText: string = '自动'; // 闪光灯模式文本
@State timerDelay: number = 3; // 定时拍照延迟秒数
build() {
Column() {
// 顶部工具栏
Row() {
// 闪光灯按钮
Button(this.flashModeText)
.fontSize(14)
.onClick(() => {
const newMode = this.flashController.cycleFlashMode();
this.flashModeText = this.flashController.getFlashModeText(newMode);
})
Blank()
// 定时拍照按钮
Button(`定时: ${this.timerDelay}s`)
.fontSize(14)
.onClick(() => {
// 循环切换延迟: 3 → 5 → 10 → 关闭 → 3
if (this.timerDelay === 3) this.timerDelay = 5;
else if (this.timerDelay === 5) this.timerDelay = 10;
else if (this.timerDelay === 10) this.timerDelay = 0;
else this.timerDelay = 3;
})
}
.width('100%')
.padding({ left: 20, right: 20 })
.justifyContent(FlexAlign.SpaceBetween)
// 倒计时显示
if (this.countdown > 0) {
Text(`${this.countdown}`)
.fontSize(80)
.fontWeight(FontWeight.Bold)
.fontColor('#FF6B6B')
.margin({ top: 50 })
}
// 连拍进度
if (this.isBursting) {
Text(this.burstProgress)
.fontSize(16)
.fontColor('#4A90D9')
.margin({ top: 20 })
}
Blank()
// 底部操作区
Row() {
// 定时拍照按钮
Button('定时拍')
.enabled(this.timerDelay > 0 && !this.isBursting && this.countdown === 0)
.onClick(() => this.startTimerCapture())
// 普通拍照按钮
Button('拍照')
.width(70)
.height(70)
.borderRadius(35)
.backgroundColor('#FF6B6B')
.enabled(!this.isBursting && this.countdown === 0)
.onClick(() => this.photoController.startBurstCapture(1, 0))
// 连拍按钮
Button(this.isBursting ? '停止' : '连拍')
.backgroundColor(this.isBursting ? '#E8A838' : '#4A90D9')
.onClick(() => {
if (this.isBursting) {
this.photoController.stopBurstCapture();
this.isBursting = false;
} else {
this.startBurstCapture();
}
})
}
.width('100%')
.padding({ left: 30, right: 30, bottom: 30 })
.justifyContent(FlexAlign.SpaceAround)
}
.width('100%')
.height('100%')
}
/**
* 启动定时拍照
*/
private startTimerCapture(): void {
this.countdown = this.timerDelay;
this.photoController.startTimerCapture(
this.timerDelay,
(remaining) => {
this.countdown = remaining;
},
() => {
this.countdown = 0;
}
);
}
/**
* 启动连拍
*/
private startBurstCapture(): void {
this.isBursting = true;
this.photoController.startBurstCapture(
10,
200,
(current, total) => {
this.burstProgress = `连拍中: ${current}/${total}`;
if (current >= total) {
this.isBursting = false;
this.burstProgress = '';
}
}
);
}
}
四、踩坑与注意事项
4.1 PhotoOutput 回调注册时机
坑:先调了 capture(),再注册 photoAvailable 回调,结果照片丢了。
解:必须在 capture() 之前注册好所有回调,否则可能丢失拍照结果。
// ❌ 错误:先拍照后注册回调
await photoOutput.capture(setting);
photoOutput.on('photoAvailable', callback); // 太晚了!
// ✅ 正确:先注册回调再拍照
photoOutput.on('photoAvailable', callback);
await photoOutput.capture(setting);
4.2 连拍时内存暴涨
坑:连拍 20 张后 App 因内存不足被系统杀掉。
解:在 photoAvailable 回调中及时处理图片数据并释放资源。每张照片处理完后立即调用 photo.release() 释放图像内存。
photoOutput.on('photoAvailable', async (photo: camera.Photo) => {
const mainImage = photo.main;
// 处理图片...
await this.savePhoto(mainImage);
// 关键:释放图像资源!
mainImage.release();
photo.release();
});
4.3 闪光灯设置不生效
坑:调了 setFlashMode() 但拍照时闪光灯没亮。
解:闪光灯模式必须在会话 start() 之后设置才生效。另外,前置摄像头通常不支持闪光灯,调用前要先检查。
// ❌ 错误:会话启动前设置闪光灯
session.setFlashMode(camera.FlashMode.FLASH_MODE_OPEN);
await session.start(); // 闪光灯设置可能被重置
// ✅ 正确:会话启动后设置闪光灯
await session.start();
session.setFlashMode(camera.FlashMode.FLASH_MODE_OPEN);
4.4 定时拍照取消后状态残留
坑:用户取消了定时拍照,但倒计时 UI 还在显示。
解:取消定时拍照时,必须同时重置所有 UI 状态。
4.5 capture() 是异步的
坑:连续快速调用 capture(),第二次调用时第一次还没完成,导致报错。
解:使用标志位或队列确保同一时间只有一个 capture 操作在进行。
private isCapturing: boolean = false;
async capture(): Promise<void> {
if (this.isCapturing) {
console.warn('[拍照] 正在拍摄中,请稍候');
return;
}
this.isCapturing = true;
try {
await this.photoOutput.capture();
} finally {
this.isCapturing = false;
}
}
4.6 图片旋转问题
坑:竖屏拍照保存后,图片变成了横屏。
解:在 PhotoCaptureSetting 中设置正确的 rotation,或者根据设备方向传感器动态设置。
五、HarmonyOS 6 适配
5.1 API 变更
| 变更项 | HarmonyOS 5.0 | HarmonyOS 6.0 |
|---|---|---|
| PhotoSession 创建 | createPhotoSession(input, preview, photo) |
保持不变 |
| 拍照质量 | QUALITY_LEVEL_HIGH/MEDIUM/LOW |
新增 QUALITY_LEVEL_ULTRA |
| 连拍 API | 手动循环 capture() |
新增 burstCapture(count, interval) |
| 照片格式 | JPEG | 新增 HEIF 格式支持 |
| 闪光灯 | 三种模式 | 新增柔光灯模式 |
5.2 迁移要点
- HEIF 格式支持:HarmonyOS 6.0 新增了 HEIF 格式,同等画质下体积约为 JPEG 的 50%,建议优先使用:
// HarmonyOS 6.0 使用 HEIF 格式
const captureSetting: camera.PhotoCaptureSetting = {
quality: camera.QualityLevel.QUALITY_LEVEL_HIGH,
format: camera.PhotoFormat.PHOTO_FORMAT_HEIF, // 新增
};
- 连拍 API 升级:6.0 新增了原生连拍方法,不再需要手动循环:
// HarmonyOS 6.0 原生连拍
await photoOutput.burstCapture({
count: 10,
interval: 200
});
- 拍照回调增强:6.0 中
photoAvailable回调新增了 EXIF 信息,可以直接获取拍摄参数。
六、总结
mindmap
root((拍照开发))
PhotoSession
创建三要素 Input + Preview + PhotoOutput
start 后才能拍照
参数配置在 start 后生效
拍照流程
注册回调 → capture → photoAvailable → 保存
capture 是异步操作
需要防止并发调用
闪光灯
四种模式 关闭/开启/自动/常亮
start 后设置才生效
前置摄像头通常不支持
定时拍照
setInterval 实现倒计时
取消时重置所有状态
倒计时结束触发 capture
连拍模式
循环调用 capture
及时释放图像内存
设置合理上限防 OOM
踩坑要点
回调注册在 capture 之前
图片旋转方向处理
连拍内存管理
核心记忆口诀:
回调先注册,capture 后触发;闪光灯 start 后设,连拍记得释内存。
下篇文章我们将深入「录像」功能,讲解 VideoSession 的使用、录像参数配置、防抖、暂停恢复等实战内容。
- 点赞
- 收藏
- 关注作者
评论(0)