鸿蒙中 自定义相机拍照
本文介绍了相机拍照功能的开发流程,重点讲解了单段式拍照的实现方法。主要内容包括:1)两种拍照方案(分段式与单段式)的特点对比;2)开发步骤详解,涵盖创建拍照输出流、设置回调、参数配置和触发拍照;3)高性能拍照功能(API 21+)的画质优先策略设置;4)拍照状态监听方法;5)完整开发流程和注意事项。特别强调了资源释放的重要性,并提供了图片保存和旋转角度获取的指导。该方案支持闪光灯、变焦等参数配置,
本文同步发表于微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
一、拍照方案
1.1 两种拍照方案
| 方案 | 特点 | 出图速度 | 画质 | 适用场景 |
|---|---|---|---|---|
| 分段式拍照 | 先输出低质量图(缩略图),后输出高质量图 | 快 | 高 | 图像处理算法需求,提升用户体验 |
| 单段式拍照 | 多帧融合+底层算法处理后返回一张高质量图 | 较慢 | 高 | 画质优先场景,支持高性能拍照设置 |
备注:本文以单段式拍照为基础进行说明。
1.2 高性能拍照
从API version 21开始,单段式拍照支持设置画质优先策略,可调整:
-
出图速度:街头抓拍等场景
-
图片质量:风景或人像拍摄等场景
二、开发步骤
2.1 导入相关模块
import { image } from '@kit.ImageKit';
import { camera } from '@kit.CameraKit';
import { fileIo as fs } from '@kit.CoreFileKit';
import { BusinessError } from '@kit.BasicServicesKit';
2.2 创建拍照输出流
通过CameraOutputCapability中的photoProfiles属性获取当前设备支持的拍照输出流,然后通过createPhotoOutput创建拍照输出流。
function getPhotoOutput(cameraManager: camera.CameraManager,
cameraOutputCapability: camera.CameraOutputCapability): camera.PhotoOutput | undefined {
let photoProfilesArray: Array<camera.Profile> = cameraOutputCapability.photoProfiles;
if (!photoProfilesArray || photoProfilesArray.length === 0) {
console.error("photoProfilesArray is null or []");
return;
}
let photoOutput: camera.PhotoOutput | undefined;
try {
photoOutput = cameraManager.createPhotoOutput(photoProfilesArray[0]);
} catch (error) {
let err = error as BusinessError;
console.error(`Failed to createPhotoOutput. error: ${err}`);
}
return photoOutput;
}
2.3 设置拍照回调
设置on('photoAvailable')回调,当拍照完成时将buffer保存为图片。
function setPhotoOutputCb(photoOutput: camera.PhotoOutput): void {
photoOutput.on('photoAvailable', (errCode: BusinessError, photo: camera.Photo): void => {
console.info('getPhoto start');
if (errCode || photo === undefined) {
console.error('getPhoto failed, err: ${errCode}');
return;
}
let imageObj: image.Image = photo.main;
imageObj.getComponent(image.ComponentType.JPEG, (errCode: BusinessError, component: image.Component): void => {
console.info('getComponent start');
if (errCode || component === undefined) {
console.error('getComponent failed');
return;
}
let buffer: ArrayBuffer;
if (component.byteBuffer) {
buffer = component.byteBuffer;
} else {
console.error('byteBuffer is null');
return;
}
// 保存图片到媒体库(建议使用安全控件SaveButton)
// 处理结束后释放资源
imageObj.release();
});
});
}
重要:buffer处理结束后需要释放资源,如果未正确释放会导致后续拍照获取不到buffer。
2.4 参数配置
配置相机的闪光灯、变焦、对焦等参数。
function configuringSession(photoSession: camera.PhotoSession): void {
// 1. 判断设备是否支持闪光灯
let flashStatus: boolean = false;
try {
flashStatus = photoSession.hasFlash();
} catch (error) {
let err = error as BusinessError;
console.error(`Failed to hasFlash. error: ${err}`);
}
console.info(`Flash light support status: ${flashStatus}`);
if (flashStatus) {
// 判断是否支持自动闪光灯模式
let flashModeStatus: boolean = false;
try {
flashModeStatus = photoSession?.isFlashModeSupported(camera.FlashMode.FLASH_MODE_AUTO);
} catch (error) {
let err = error as BusinessError;
console.error(`Failed to check flash mode support. error: ${err}`);
}
if (flashModeStatus) {
// 设置自动闪光灯模式
try {
photoSession?.setFlashMode(camera.FlashMode.FLASH_MODE_AUTO);
} catch (error) {
let err = error as BusinessError;
console.error(`Failed to set flash mode. error: ${err}`);
}
}
}
// 2. 判断是否支持连续自动对焦模式
let focusModeStatus: boolean = false;
try {
focusModeStatus = photoSession?.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO);
} catch (error) {
let err = error as BusinessError;
console.error(`Failed to check focus mode support. error: ${err}`);
}
if (focusModeStatus) {
// 设置连续自动对焦模式
try {
photoSession?.setFocusMode(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO);
} catch (error) {
let err = error as BusinessError;
console.error(`Failed to set focus mode. error: ${err}`);
}
}
// 3. 获取相机支持的可变焦距比范围
let zoomRatioRange: Array<number> = [];
try {
zoomRatioRange = photoSession?.getZoomRatioRange();
} catch (error) {
let err = error as BusinessError;
console.error(`Failed to get zoom ratio range. error: ${err}`);
}
if (zoomRatioRange.length <= 0) {
return;
}
// 设置可变焦距比
try {
photoSession?.setZoomRatio(zoomRatioRange[0]);
} catch (error) {
let err = error as BusinessError;
console.error(`Failed to set zoom ratio. error: ${err}`);
}
}
2.5 触发拍照
通过photoOutput.capture方法执行拍照任务。
function capture(captureLocation: camera.Location, photoOutput: camera.PhotoOutput): void {
let settings: camera.PhotoCaptureSetting = {
quality: camera.QualityLevel.QUALITY_LEVEL_HIGH, // 设置图片质量高
rotation: camera.ImageRotation.ROTATION_0, // 设置图片旋转角度
location: captureLocation, // 设置图片地理位置
mirror: false // 设置镜像使能开关(默认关)
};
try {
photoOutput.capture(settings, (err: BusinessError) => {
if (err) {
console.error(`Failed to capture the photo. error: ${err}`);
return;
}
console.info('Photo capture request success.');
});
} catch (error) {
console.error(`capture call failed. error: ${error}`);
}
}
PhotoCaptureSetting参数:
| 参数 | 类型 | 说明 |
|---|---|---|
quality |
QualityLevel | 图片质量(低/中/高) |
rotation |
ImageRotation | 图片旋转角度 |
location |
Location | 图片地理位置信息 |
mirror |
boolean | 镜像使能开关(默认关) |
三、高性能拍照(API 21+)
3.1 画质优先策略
单段式拍照支持两种画质优先策略:
| 策略 | 枚举值 | 说明 |
|---|---|---|
| 速度优先 | SPEED | 降低画质来提升拍照速度(默认) |
| 画质优先 | HIGH_QUALITY | 通过较长耗时得到更高画质的图片 |
注意:仅单段式拍照支持设置画质优先策略。若在分段式拍照中设置,该设置将无效。
3.2 设置画质优先策略的接口
| 接口 | 说明 |
|---|---|
isPhotoQualityPrioritizationSupported |
查询当前设备是否支持指定的画质优先策略 |
setPhotoQualityPrioritization |
设置画质优先策略 |
3.3 调用时机
高性能拍照相关接口需要在会话管理流程的使能步骤中调用。
方式一:在commitConfig之后调用
async function startSession(videoSession: camera.VideoSession,
cameraInput: camera.CameraInput,
previewOutput: camera.PreviewOutput,
photoOutput: camera.PhotoOutput): Promise<void> {
// ... 添加输入输出流 ...
try {
await videoSession.commitConfig();
} catch (error) {
console.error(`Failed to commitConfig. error: ${error}`);
return;
}
try {
await videoSession.start();
} catch (error) {
console.error(`Failed to start. error: ${error}`);
}
// commitConfig之后调用
modeSwitchToHigh(videoSession, photoOutput);
}
async function modeSwitchToHigh(videoSession: camera.VideoSession,
photoOutput: camera.PhotoOutput): Promise<void> {
try {
if (videoSession) {
let quality: camera.PhotoQualityPrioritization =
camera.PhotoQualityPrioritization.HIGH_QUALITY;
let isSupported = photoOutput.isPhotoQualityPrioritizationSupported(quality);
if (isSupported) {
photoOutput.setPhotoQualityPrioritization(quality);
} else {
console.error(`session is not supported`);
}
}
} catch {
console.error(`catch error`);
}
}
方式二:在commitConfig之前调用
async function startSession(videoSession: camera.VideoSession,
cameraInput: camera.CameraInput,
previewOutput: camera.PreviewOutput,
photoOutput: camera.PhotoOutput): Promise<void> {
// ... 添加输入输出流 ...
// commitConfig之前调用
modeSwitchToHigh(videoSession, photoOutput);
try {
await videoSession.commitConfig();
} catch (error) {
console.error(`Failed to commitConfig. error: ${error}`);
return;
}
try {
await videoSession.start();
} catch (error) {
console.error(`Failed to start. error: ${error}`);
}
}
四、状态监听
4.1 监听拍照开始
function onPhotoOutputCaptureStart(photoOutput: camera.PhotoOutput): void {
photoOutput.on('captureStartWithInfo', (err: BusinessError, captureStartInfo: camera.CaptureStartInfo) => {
if (err !== undefined && err.code !== 0) {
return;
}
console.info(`photo capture started, captureId: ${captureStartInfo.captureId}`);
});
}
4.2 监听拍照结束
function onPhotoOutputCaptureEnd(photoOutput: camera.PhotoOutput): void {
photoOutput.on('captureEnd', (err: BusinessError, captureEndInfo: camera.CaptureEndInfo) => {
if (err !== undefined && err.code !== 0) {
return;
}
console.info(`photo capture end, captureId: ${captureEndInfo.captureId}`);
console.info(`frameCount: ${captureEndInfo.frameCount}`);
});
}
4.3 监听可拍下一张
function onPhotoOutputCaptureReady(photoOutput: camera.PhotoOutput): void {
photoOutput.on('captureReady', (err: BusinessError) => {
if (err !== undefined && err.code !== 0) {
return;
}
console.info(`photo capture ready`);
});
}
4.4 监听错误
function onPhotoOutputError(photoOutput: camera.PhotoOutput): void {
photoOutput.on('error', (error: BusinessError) => {
console.error(`Photo output error code: ${error.code}`);
});
}
五、开发流程
导入模块
↓
创建拍照输出流(createPhotoOutput)
↓
设置拍照回调(on('photoAvailable'))
↓
配置相机参数(闪光灯、对焦、变焦等)
↓
(可选)设置画质优先策略(高性能拍照)
↓
触发拍照(capture)
↓
监听拍照状态(开始、结束、错误)
↓
保存图片到媒体库
↓
释放资源
六、注意事项
6.1 资源释放
重要:buffer处理结束后需要释放资源,如果未正确释放资源会导致后续拍照获取不到buffer。
6.2 图片保存
如需要在图库中看到所保存的图片、视频资源,需要将其保存到媒体库,保存方式请参考:保存媒体库资源。
6.3 旋转角度
获取拍照旋转角度的方法为:通过PhotoOutput中的getPhotoRotation方法获取rotation实际的值。
鸿蒙相机拍照支持分段式拍照和单段式拍照,通过PhotoOutput创建拍照输出流、配置闪光灯/对焦/变焦等参数、调用capture触发拍照,API 21+支持设置画质优先策略以平衡出图速度和图片质量。
更多推荐



所有评论(0)