HarmonyOS鸿蒙Next应用如何自定义相机实现拍照功能?
HarmonyOS鸿蒙Next应用如何自定义相机实现拍照功能?
鸿蒙应用如何自定义相机实现拍照功能?
自定义相机拍照 :
拍照是相机的最重要功能之一,拍照模块依托于相机复杂的逻辑,为确保用户拍摄的照片质量,提供了对分辨率、闪光灯、焦距、照片质量及旋转角度等设置的调整选项。本文将以自定义相机为例,分别介绍基础拍照、参数配置、分段式拍照、HDR Vivid拍照以及动图拍摄等功能。通过多样化的拍摄方式,可以更好地满足用户的个性化需求。
其中,分段式拍照、HDR Vivid拍照和动图拍摄,分别从效率、画质和内容三大核心方面对自定义相机进行了优化。用户可根据实际需求,在追求快速反馈、细节保留或动态记录时,灵活选择单一或多种功能组合使用,最大限度满足个性化拍摄场景,全面提升拍照体验。
基础拍照
场景描述
基础拍照功能是自定义相机应用的重要功能,用户在切换到拍照模式后可实时预览取景画面,并通过快门按钮快速拍摄照片,此外用户还可以设置不同的拍照参数,应用会将拍到的画面保存为图片。
流程图:

1、申请相关权限
在开发相机应用时,需要先参考申请相关权限。
2、创建拍照输出流
通过CameraOutputCapability类中的photoProfiles属性,能够获取设备当前支持的拍照输出流配置,根据业务场景选择合适的输出流配置。最终,可通过调用createPhotoOutput()方法,并传入选定的输出流配置,完成拍照输出流的创建。
3、设置拍照photoAvailable回调
注册全质量图上报监听后,触发拍照操作即可通过回调接收图片数据。具体实现时,需通过photoOutput.on(‘photoAvailable’)接口监听buffer获取事件。完成回调设置后,调用photoOutput的capture()方法触发拍摄,此时拍照生成的buffer将回传至注册的回调中。
4、参数配置
通过配置相机参数可调节闪光灯、变焦、焦距等拍照功能。相关功能的实现主要依托PhotoSession(普通拍照模式会话类)的接口方法完成。
设置闪光灯:设置闪光灯。
设置对焦模式:实现点击对焦。
设置焦点:实现点击对焦。
设置变焦比:设置相机焦距。
设置拍照旋转角度
拍照的旋转角度与重力方向(即设备旋转角度)相关。调用PhotoOutput类中的getPhotoRotation()可以获取到拍照的旋转角度。详细请参见适配相机旋转角度(ArkTS) 。
deviceDegree:设备旋转角度。获取方式请见计算设备旋转角度。
5、触发拍照
通过photoOutput类的capture()方法,执行拍照任务。
可以通过参数调整拍照的设置,例如调整拍照质量、拍照旋转角度、位置信息以及是否开启镜像等。
6、释放资源
调用CameraOutput类的release()方法,释放输出资源。

更多关于HarmonyOS鸿蒙Next应用如何自定义相机实现拍照功能?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
一、结论
鸿蒙工具包已经提供了完整的一键扫码和一键唤起系统相机的功能,但是定制化的需求无法满足。此时我们就需要自定义相机去实现功能。
通过系统提供的CameraKit调用相关相机API进行相机设备调用,相机视频流来实现。
如果只是简单的调用相机进行拍照和录像的需求,只需要调用系统相机即可。
二、代码实现和详细解释
1.设置相机界面
2.选择相机摄像头实例 根据cameraKit提供的CameraManager获取相机管理实例,拿到设备的相机列表,一般分为前后两个。选择你要用的相机。
3.相机输出流 传入你选择的相机实例给cameraManager.createCameraInput创建相机输出流,开启会话后cameraInput.open,进行相机的参数配置(拍照还是摄像模式,闪光灯,焦距比)
4.配置相机会话信息 创建会话,将输入流,输出流,拍照,摄像,绑定到会话上。完事之后,开启会话,相机流就能正常输出。你去操作拍照摄像也可以正常操作。你可以理解会话为一个组合器。
5.退出界面销毁相机 相机资源不释放,会导致再次初始化黑屏,甚至影响系统相机等异常问题。
import { camera } from '@kit.CameraKit';
import { image } from '@kit.ImageKit';
import { BusinessError } from '@kit.BasicServicesKit';
export class CameraMgr {
private TAG: string = "CameraMgr";
private static mCameraMgr: CameraMgr | null = null;
private mPhotoOutput: camera.PhotoOutput | undefined = undefined;
private mPhotoSession: camera.PhotoSession | undefined = undefined;
private mCameraInput: camera.CameraInput | undefined = undefined;
private mPreviewOutput: camera.PreviewOutput | undefined = undefined;
public static Ins(): CameraMgr {
if (CameraMgr.mCameraMgr) {
return CameraMgr.mCameraMgr
}
CameraMgr.mCameraMgr = new CameraMgr();
return CameraMgr.mCameraMgr
}
/**
* 初始化相机
* @param baseContext
* @param surfaceId
*/
public async initCamera(baseContext: Context, surfaceId: string) {
// 创建CameraManager对象
let cameraManager: camera.CameraManager = camera.getCameraManager(baseContext);
if (!cameraManager) {
console.error("camera.getCameraManager error");
return;
}
// 监听相机状态变化
cameraManager.on('cameraStatus', (err: BusinessError, cameraStatusInfo: camera.CameraStatusInfo) => {
if (err !== undefined && err.code !== 0) {
console.error('cameraStatus with errorCode = ' + err.code);
return;
}
console.info(`camera : ${cameraStatusInfo.camera.cameraId}`);
console.info(`status: ${cameraStatusInfo.status}`);
});
// 获取相机列表
let cameraArray: Array<camera.CameraDevice> = cameraManager.getSupportedCameras();
if (cameraArray.length <= 0) {
console.error("cameraManager.getSupportedCameras error");
return;
}
for (let index = 0; index < cameraArray.length; index++) {
console.info('cameraId : ' + cameraArray[index].cameraId); // 获取相机ID
console.info('cameraPosition : ' + cameraArray[index].cameraPosition); // 获取相机位置
console.info('cameraType : ' + cameraArray[index].cameraType); // 获取相机类型
console.info('connectionType : ' + cameraArray[index].connectionType); // 获取相机连接类型
}
// 创建相机输入流
let cameraInput: camera.CameraInput | undefined = undefined;
try {
// 配置后置摄像头
cameraInput = cameraManager.createCameraInput(cameraArray[0]);
} catch (error) {
let err = error as BusinessError;
console.error('Failed to createCameraInput errorCode = ' + err.code);
}
if (cameraInput === undefined) {
return;
}
this.mCameraInput = cameraInput;
// 监听cameraInput错误信息
let cameraDevice: camera.CameraDevice = cameraArray[0];
cameraInput.on('error', cameraDevice, (error: BusinessError) => {
console.error(`Camera input error code: ${error.code}`);
})
// 打开相机
await cameraInput.open();
// 获取支持的模式类型
let sceneModes: Array<camera.SceneMode> = cameraManager.getSupportedSceneModes(cameraArray[0]);
let isSupportPhotoMode: boolean = sceneModes.indexOf(camera.SceneMode.NORMAL_PHOTO) >= 0;
if (!isSupportPhotoMode) {
console.error('photo mode not support');
return;
}
// 获取相机设备支持的输出流能力
let cameraOutputCap: camera.CameraOutputCapability = cameraManager.getSupportedOutputCapability(cameraArray[0], camera.SceneMode.NORMAL_PHOTO);
if (!cameraOutputCap) {
console.error("cameraManager.getSupportedOutputCapability error");
return;
}
console.info("outputCapability: " + JSON.stringify(cameraOutputCap));
let previewProfilesArray: Array<camera.Profile> = cameraOutputCap.previewProfiles;
if (!previewProfilesArray) {
console.error("createOutput previewProfilesArray == null || undefined");
}
let photoProfilesArray: Array<camera.Profile> = cameraOutputCap.photoProfiles;
if (!photoProfilesArray) {
console.error("createOutput photoProfilesArray == null || undefined");
}
// 创建预览输出流
let previewOutput: camera.PreviewOutput | undefined = undefined;
try {
previewOutput = cameraManager.createPreviewOutput(previewProfilesArray[0], surfaceId);
} catch (error) {
let err = error as BusinessError;
console.error(`Failed to create the PreviewOutput instance. error code: ${err.code}`);
}
if (previewOutput === undefined) {
return;
}
this.mPreviewOutput = previewOutput;
// 监听预览输出错误信息
previewOutput.on('error', (error: BusinessError) => {
console.error(`Preview output error code: ${error.code}`);
});
// 创建拍照输出流
let photoOutput: camera.PhotoOutput | undefined = undefined;
try {
photoOutput = cameraManager.createPhotoOutput(photoProfilesArray[0]);
} catch (error) {
let err = error as BusinessError;
console.error('Failed to createPhotoOutput errorCode = ' + err.code);
}
if (photoOutput === undefined) {
return;
}
this.mPhotoOutput = photoOutput;
//调用上面的回调函数来保存图片
this.setPhotoOutput();
//创建会话
let photoSession: camera.PhotoSession | undefined = undefined;
try {
photoSession = cameraManager.createSession(camera.SceneMode.NORMAL_PHOTO) as camera.PhotoSession;
} catch (error) {
let err = error as BusinessError;
console.error('Failed to create the session instance. errorCode = ' + err.code);
}
if (photoSession === undefined) {
return;
}
this.mPhotoSession = photoSession;
// 监听session错误信息
photoSession.on('error', (error: BusinessError) => {
console.error(`Capture session error code: ${error.code}`);
});
// 开始配置会话
try {
photoSession.beginConfig();
} catch (error) {
let err = error as BusinessError;
console.error('Failed to beginConfig. errorCode = ' + err.code);
}
// 向会话中添加相机输入流
try {
photoSession.addInput(cameraInput);
} catch (error) {
let err = error as BusinessError;
console.error('Failed to addInput. errorCode = ' + err.code);
}
// 向会话中添加预览输出流
try {
photoSession.addOutput(previewOutput);
} catch (error) {
let err = error as BusinessError;
console.error('Failed to addOutput(previewOutput). errorCode = ' + err.code);
}
// 向会话中添加拍照输出流
try {
photoSession.addOutput(photoOutput);
} catch (error) {
let err = error as BusinessError;
console.error('Failed to addOutput(photoOutput). errorCode = ' + err.code);
}
// 提交会话配置
await photoSession.commitConfig();
// 启动会话
await photoSession.start().then(() => {
console.info('Promise returned to indicate the session start success.');
});
// 判断设备是否支持闪光灯
let flashStatus: boolean = false;
try {
flashStatus = photoSession.hasFlash();
} catch (error) {
let err = error as BusinessError;
console.error('Failed to hasFlash. errorCode = ' + err.code);
}
console.info('Returned with the flash light support status:' + flashStatus);
if (flashStatus) {
// 判断是否支持自动闪光灯模式
let flashModeStatus: boolean = false;
try {
let status: boolean = photoSession.isFlashModeSupported(camera.FlashMode.FLASH_MODE_AUTO);
flashModeStatus = status;
} catch (error) {
let err = error as BusinessError;
console.error('Failed to check whether the flash mode is supported. errorCode = ' + err.code);
}
if(flashModeStatus) {
// 设置自动闪光灯模式
try {
photoSession.setFlashMode(camera.FlashMode.FLASH_MODE_AUTO);
} catch (error) {
let err = error as BusinessError;
console.error('Failed to set the flash mode. errorCode = ' + err.code);
}
}
}
// 判断是否支持连续自动变焦模式
let focusModeStatus: boolean = false;
try {
let status: boolean = photoSession.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO);
focusModeStatus = status;
} catch (error) {
let err = error as BusinessError;
console.error('Failed to check whether the focus mode is supported. errorCode = ' + err.code);
}
if (focusModeStatus) {
// 设置连续自动变焦模式
try {
photoSession.setFocusMode(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO);
} catch (error) {
let err = error as BusinessError;
console.error('Failed to set the focus mode. errorCode = ' + err.code);
}
}
// 获取相机支持的可变焦距比范围
let zoomRatioRange: Array<number> = [];
try {
zoomRatioRange = photoSession.getZoomRatioRange();
} catch (error) {
let err = error as BusinessError;
console.error('Failed to get the zoom ratio range. errorCode = ' + err.code);
}
if (zoomRatioRange.length <= 0) {
return;
}
// 设置可变焦距比
try {
photoSession.setZoomRatio(zoomRatioRange[0]);
} catch (error) {
let err = error as BusinessError;
console.error('Failed to set the zoom ratio value. errorCode = ' + err.code);
}
}
/**
* 相机拍照
*/
public capturePhoto(){
let photoCaptureSetting: camera.PhotoCaptureSetting = {
quality: camera.QualityLevel.QUALITY_LEVEL_HIGH, // 设置图片质量高
rotation: camera.ImageRotation.ROTATION_0 // 设置图片旋转角度0
}
// 使用当前拍照设置进行拍照
this.mPhotoOutput?.capture(photoCaptureSetting, (err: BusinessError) => {
if (err) {
console.error(`Failed to capture the photo ${err.message}`);
return;
}
console.info('Callback invoked to indicate the photo capture request success.');
});
}
/**
* 销毁相机
*/
public async destroyCamera(){
// 需要在拍照结束之后调用以下关闭摄像头和释放会话流程,避免拍照未结束就将会话释放。
// 停止当前会话
await this.mPhotoSession?.stop();
// 释放相机输入流
await this.mCameraInput?.close();
// 释放预览输出流
await this.mPreviewOutput?.release();
// 释放拍照输出流
await this.mPhotoOutput?.release();
// 释放会话
await this.mPhotoSession?.release();
// 会话置空
this.mPhotoSession = undefined;
}
/**
* 设置相机拍照回调
*/
public setPhotoOutput(){
// 设置回调之后,调用photoOutput的capture方法,就会将拍照的buffer回传到回调中
this.mPhotoOutput?.on('photoAvailable', (errCode: BusinessError, photo: camera.Photo): void => {
console.info('getPhoto start');
console.info(`err: ${JSON.stringify(errCode)}`);
if (errCode || photo === undefined) {
console.error('getPhoto failed');
return;
}
let imageObj = 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;
}
// 如需要在图库中看到所保存的图片、视频资源,请使用用户无感的安全控件创建媒体资源。
// buffer处理结束后需要释放该资源,如果未正确释放资源会导致后续拍照获取不到buffer
imageObj.release();
});
});
}
}
HarmonyOS Next中自定义相机需使用CameraKit API。首先在module.json5中声明相机权限,然后通过CameraManager获取相机列表并创建CaptureSession。使用SurfaceProvider绑定预览画面,通过CaptureRequest配置拍照参数。调用capture()方法执行拍照,图像数据通过ImageReceiver回调获取。
在HarmonyOS Next中,自定义相机并实现拍照功能主要通过CameraKit框架实现。以下是核心步骤和代码要点:
1. 权限与配置
- 声明权限:在
module.json5中申请ohos.permission.CAMERA权限。 - 配置输出能力:通过
CameraOutputCapability类获取相机支持的输出流配置(如预览、拍照分辨率)。
2. 初始化相机
- 使用
CameraManager获取设备相机列表,选择后置或前置摄像头。 - 通过
CameraInput创建相机输入流,绑定到Camera实例。
3. 配置预览与拍照输出
- 预览输出:创建
PreviewOutput实例,关联XComponent组件作为预览显示界面。 - 拍照输出:创建
PhotoOutput实例,设置拍照参数(如图像格式、质量)。
4. 会话管理与拍照触发
- 创建
CaptureSession,绑定CameraInput、PreviewOutput和PhotoOutput。 - 调用
session.commitConfig()提交配置,session.start()启动预览。 - 通过
PhotoOutput.capture()触发拍照,在回调中获取图像数据(保存为PixelMap或文件)。
5. 资源释放
拍照完成后,需停止会话并释放相机资源,避免占用。
示例代码片段(ArkTS):
import camera from '@ohos.multimedia.camera';
import image from '@ohos.multimedia.image';
// 1. 获取CameraManager实例
let cameraManager = camera.getCameraManager(context);
// 2. 获取相机设备并创建输入流
let cameras = cameraManager.getSupportedCameras();
let cameraInput = cameraManager.createCameraInput(cameras[0]);
// 3. 创建预览输出(关联XComponent)
let previewOutput = cameraManager.createPreviewOutput(previewProfile);
// 4. 创建拍照输出
let photoProfile = photoProfiles[0]; // 从输出能力中获取
let photoOutput = cameraManager.createPhotoOutput(photoProfile);
// 5. 创建会话并配置
let captureSession = cameraManager.createCaptureSession();
captureSession.beginConfig();
captureSession.addInput(cameraInput);
captureSession.addOutput(previewOutput);
captureSession.addOutput(photoOutput);
await captureSession.commitConfig();
await captureSession.start();
// 6. 触发拍照
photoOutput.capture((err, photo) => {
if (!err) {
photo.save(); // 保存图像
}
});
注意事项:
- 需适配设备差异,动态选择支持的输出配置。
- 拍照过程需处理异步回调,确保图像正确保存。
- 建议参考官方示例(
Camera组件开发指南)进行完整实现。
通过以上步骤,可灵活控制相机参数(如对焦、曝光),实现定制化拍照功能。

