文档管理中心
指南媒体Camera Kit(相机服务)开发相机应用基础能力(ArkTS)HDR Vivid相机拍照(ArkTS)

HDR Vivid相机拍照(ArkTS)

本文导读

HarmonyOS支持调用接口拍摄HDR Vivid照片,可以拍出层次表现更细腻、光影细节更丰富的画面,提升画面质感,呈现更卓越的视觉效果。

当前示例提供完整的HDR Vivid拍照开发步骤,方便开发者实现HDR拍照的功能。更多HDR Vivid的开发指导,请参考使用HDR Vivid特性开发媒体应用

在参考以下示例前,建议开发者查看相机开发指导(ArkTS)的具体章节,了解设备输入会话管理拍照等单个流程。

开发步骤

  1. 导入接口。

    收起
    自动换行
    深色代码主题
    复制
    1. import { camera } from '@kit.CameraKit';
    2. import { colorSpaceManager } from '@kit.ArkGraphics2D';
    3. import { image } from '@kit.ImageKit';
    4. import { BusinessError } from '@kit.BasicServicesKit';
    5. import { fileIo } from '@kit.CoreFileKit';
    6. import { photoAccessHelper } from '@kit.MediaLibraryKit';
  2. 查询支持的色彩空间。

    收起
    自动换行
    深色代码主题
    复制
    1. function getSupportedColorSpaces(session: camera.PhotoSession): Array<colorSpaceManager.ColorSpace> {
    2. let colorSpaces: Array<colorSpaceManager.ColorSpace> = [];
    3. try {
    4. colorSpaces = session.getSupportedColorSpaces();
    5. } catch (error) {
    6. let err = error as BusinessError;
    7. console.error(`The getSupportedColorSpaces call failed. error code: ${err.code}`);
    8. }
    9. return colorSpaces;
    10. }
  3. 设置色彩空间。

    如果是SDR拍照色彩空间需要设置为SRGB,如果是HDR拍照色彩空间需要设置为DISPLAY_P3。具体参考setColorSpace

    收起
    自动换行
    深色代码主题
    复制
    1. function setColorSpaceBeforeCommitConfig(session: camera.PhotoSession, isHdr: boolean): void {
    2. let colorSpace: colorSpaceManager.ColorSpace = isHdr? colorSpaceManager.ColorSpace.DISPLAY_P3 : colorSpaceManager.ColorSpace.SRGB;
    3. let colorSpaces: Array<colorSpaceManager.ColorSpace> = getSupportedColorSpaces(session);
    4. let isSupportedColorSpaces = colorSpaces.indexOf(colorSpace) >= 0;
    5. if (isSupportedColorSpaces) {
    6. console.info(`setColorSpace: ${colorSpace}`);
    7. session.setColorSpace(colorSpace);
    8. let activeColorSpace:colorSpaceManager.ColorSpace = session.getActiveColorSpace();
    9. console.info(`activeColorSpace: ${activeColorSpace}`);
    10. } else {
    11. console.info(`colorSpace: ${colorSpace} is not support`);
    12. }
    13. }
  4. 实现HDR拍照。

    在提交会话配置前执行步骤3设置色彩空间,其余流程按照正常拍照流程开发。

    收起
    自动换行
    深色代码主题
    复制
    1. async function savePicture(buffer: ArrayBuffer, img: image.Image, context: Context): Promise<void> {
    2. let accessHelper: photoAccessHelper.PhotoAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
    3. let options: photoAccessHelper.CreateOptions = {
    4. title: Date.now().toString()
    5. };
    6. let photoUri: string = await accessHelper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg', options);
    7. // createAsset的调用需要ohos.permission.READ_IMAGEVIDEO和ohos.permission.WRITE_IMAGEVIDEO的权限
    8. let file: fileIo.File = fileIo.openSync(photoUri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
    9. await fileIo.write(file.fd, buffer);
    10. fileIo.closeSync(file);
    11. img.release();
    12. }
    13. function setPhotoOutputCb(photoOutput: camera.PhotoOutput, context: Context): void {
    14. // 设置回调之后,调用photoOutput的capture方法,就会将拍照的buffer回传到回调中
    15. photoOutput.on('photoAvailable', (errCode: BusinessError, photo: camera.Photo): void => {
    16. console.info('getPhoto start');
    17. console.info(`err: ${JSON.stringify(errCode)}`);
    18. if (errCode || photo === undefined) {
    19. console.error('getPhoto failed');
    20. return;
    21. }
    22. let imageObj = photo.main;
    23. imageObj.getComponent(image.ComponentType.JPEG, (errCode: BusinessError, component: image.Component): void => {
    24. console.info('getComponent start');
    25. if (errCode || component === undefined) {
    26. console.error('getComponent failed');
    27. return;
    28. }
    29. let buffer: ArrayBuffer;
    30. if (component.byteBuffer) {
    31. buffer = component.byteBuffer;
    32. } else {
    33. console.error('byteBuffer is null');
    34. return;
    35. }
    36. savePicture(buffer, imageObj, context);
    37. });
    38. });
    39. }
    40. async function cameraHdrShootingCase(context: Context, surfaceId: string): Promise<void> {
    41. // 创建CameraManager对象
    42. let cameraManager: camera.CameraManager = camera.getCameraManager(context);
    43. if (!cameraManager) {
    44. console.error("camera.getCameraManager error");
    45. return;
    46. }
    47. // 监听相机状态变化
    48. cameraManager.on('cameraStatus', (err: BusinessError, cameraStatusInfo: camera.CameraStatusInfo) => {
    49. if (err !== undefined && err.code !== 0) {
    50. console.error('cameraStatus with errorCode = ' + err.code);
    51. return;
    52. }
    53. console.info(`camera : ${cameraStatusInfo.camera.cameraId}`);
    54. console.info(`status: ${cameraStatusInfo.status}`);
    55. });
    56. // 获取相机列表
    57. let cameraArray: Array<camera.CameraDevice> = cameraManager.getSupportedCameras();
    58. if (cameraArray.length <= 0) {
    59. console.error("cameraManager.getSupportedCameras error");
    60. return;
    61. }
    62. for (let index = 0; index < cameraArray.length; index++) {
    63. console.info('cameraId : ' + cameraArray[index].cameraId); // 获取相机ID
    64. console.info('cameraPosition : ' + cameraArray[index].cameraPosition); // 获取相机位置
    65. console.info('cameraType : ' + cameraArray[index].cameraType); // 获取相机类型
    66. console.info('connectionType : ' + cameraArray[index].connectionType); // 获取相机连接类型
    67. }
    68. // 创建相机输入流
    69. let cameraInput: camera.CameraInput | undefined = undefined;
    70. try {
    71. cameraInput = cameraManager.createCameraInput(cameraArray[0]);
    72. } catch (error) {
    73. let err = error as BusinessError;
    74. console.error('Failed to createCameraInput errorCode = ' + err.code);
    75. }
    76. if (cameraInput === undefined) {
    77. return;
    78. }
    79. // 监听cameraInput错误信息
    80. let cameraDevice: camera.CameraDevice = cameraArray[0];
    81. cameraInput.on('error', cameraDevice, (error: BusinessError) => {
    82. console.error(`Camera input error code: ${error.code}`);
    83. })
    84. // 打开相机
    85. await cameraInput.open();
    86. // 获取支持的模式类型
    87. let sceneModes: Array<camera.SceneMode> = cameraManager.getSupportedSceneModes(cameraArray[0]);
    88. let isSupportPhotoMode: boolean = sceneModes.indexOf(camera.SceneMode.NORMAL_PHOTO) >= 0;
    89. if (!isSupportPhotoMode) {
    90. console.error('photo mode not support');
    91. return;
    92. }
    93. // 获取相机设备支持的输出流能力
    94. let cameraOutputCap: camera.CameraOutputCapability = cameraManager.getSupportedOutputCapability(cameraArray[0], camera.SceneMode.NORMAL_PHOTO);
    95. if (!cameraOutputCap) {
    96. console.error("cameraManager.getSupportedOutputCapability error");
    97. return;
    98. }
    99. console.info("outputCapability: " + JSON.stringify(cameraOutputCap));
    100. let previewProfilesArray: Array<camera.Profile> = cameraOutputCap.previewProfiles;
    101. if (!previewProfilesArray) {
    102. console.error("createOutput previewProfilesArray == null || undefined");
    103. }
    104. let photoProfilesArray: Array<camera.Profile> = cameraOutputCap.photoProfiles;
    105. if (!photoProfilesArray) {
    106. console.error("createOutput photoProfilesArray == null || undefined");
    107. }
    108. // 创建预览输出流,其中参数 surfaceId 参考上文 XComponent 组件,预览流为XComponent组件提供的surface
    109. let previewOutput: camera.PreviewOutput | undefined = undefined;
    110. try {
    111. previewOutput = cameraManager.createPreviewOutput(previewProfilesArray[0], surfaceId);
    112. } catch (error) {
    113. let err = error as BusinessError;
    114. console.error(`Failed to create the PreviewOutput instance. error code: ${err.code}`);
    115. }
    116. if (previewOutput === undefined) {
    117. return;
    118. }
    119. // 监听预览输出错误信息
    120. previewOutput.on('error', (error: BusinessError) => {
    121. console.error(`Preview output error code: ${error.code}`);
    122. });
    123. // 创建拍照输出流
    124. let photoOutput: camera.PhotoOutput | undefined = undefined;
    125. try {
    126. photoOutput = cameraManager.createPhotoOutput(photoProfilesArray[0]);
    127. } catch (error) {
    128. let err = error as BusinessError;
    129. console.error('Failed to createPhotoOutput errorCode = ' + err.code);
    130. }
    131. if (photoOutput === undefined) {
    132. return;
    133. }
    134. // 调用上面的回调函数来保存图片
    135. setPhotoOutputCb(photoOutput, context);
    136. // 创建会话
    137. let photoSession: camera.PhotoSession | undefined = undefined;
    138. try {
    139. photoSession = cameraManager.createSession(camera.SceneMode.NORMAL_PHOTO) as camera.PhotoSession;
    140. } catch (error) {
    141. let err = error as BusinessError;
    142. console.error('Failed to create the session instance. errorCode = ' + err.code);
    143. }
    144. if (photoSession === undefined) {
    145. return;
    146. }
    147. // 监听session错误信息
    148. photoSession.on('error', (error: BusinessError) => {
    149. console.error(`Capture session error code: ${error.code}`);
    150. });
    151. // 开始配置会话
    152. try {
    153. photoSession.beginConfig();
    154. } catch (error) {
    155. let err = error as BusinessError;
    156. console.error('Failed to beginConfig. errorCode = ' + err.code);
    157. }
    158. // 向会话中添加相机输入流
    159. try {
    160. photoSession.addInput(cameraInput);
    161. } catch (error) {
    162. let err = error as BusinessError;
    163. console.error('Failed to addInput. errorCode = ' + err.code);
    164. }
    165. // 向会话中添加预览输出流
    166. try {
    167. photoSession.addOutput(previewOutput);
    168. } catch (error) {
    169. let err = error as BusinessError;
    170. console.error('Failed to addOutput(previewOutput). errorCode = ' + err.code);
    171. }
    172. // 向会话中添加拍照输出流
    173. try {
    174. photoSession.addOutput(photoOutput);
    175. } catch (error) {
    176. let err = error as BusinessError;
    177. console.error('Failed to addOutput(photoOutput). errorCode = ' + err.code);
    178. }
    179. // 设置色彩空间
    180. setColorSpaceBeforeCommitConfig(photoSession, true);
    181. // 提交会话配置
    182. await photoSession.commitConfig();
    183. // 启动会话
    184. await photoSession.start().then(() => {
    185. console.info('Promise returned to indicate the session start success.');
    186. });
    187. let photoCaptureSetting: camera.PhotoCaptureSetting = {
    188. quality: camera.QualityLevel.QUALITY_LEVEL_HIGH, // 设置图片质量高
    189. rotation: camera.ImageRotation.ROTATION_0 // 设置图片旋转角度0
    190. }
    191. // 使用当前拍照设置进行拍照
    192. photoOutput.capture(photoCaptureSetting, (err: BusinessError) => {
    193. if (err) {
    194. console.error(`Failed to capture the photo ${err.message}`);
    195. return;
    196. }
    197. console.info('Callback invoked to indicate the photo capture request success.');
    198. });
    199. // 需要在拍照结束之后调用以下关闭摄像头和释放会话流程,避免拍照未结束就将会话释放。
    200. // 停止当前会话
    201. await photoSession.stop();
    202. // 释放相机输入流
    203. await cameraInput.close();
    204. // 释放预览输出流
    205. await previewOutput.release();
    206. // 释放拍照输出流
    207. await photoOutput.release();
    208. // 释放会话
    209. await photoSession.release();
    210. // 会话置空
    211. photoSession = undefined;
    212. }
在 指南 中进行搜索
请输入您想要搜索的关键词