HarmonyOS鸿蒙NEXT应用开发如何通过CameraManager动态配置与切换相机预览/拍照的分辨率?

HarmonyOS鸿蒙NEXT应用开发如何通过CameraManager动态配置与切换相机预览/拍照的分辨率? 希望实现一个让用户能在不同分辨率之间切换的功能,并保证预览不变形

3 回复

更多关于HarmonyOS鸿蒙NEXT应用开发如何通过CameraManager动态配置与切换相机预览/拍照的分辨率?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS NEXT中,通过CameraManager动态配置与切换相机分辨率,需使用CameraOutputCapability类获取设备支持的分辨率列表。在创建PreviewOutput或PhotoOutput时,通过setResolution()方法设置具体分辨率。切换时需先停止当前输出流,修改分辨率参数后重新配置并启动。注意确保新分辨率在设备支持范围内,并协调预览与拍照输出间的一致性。

在HarmonyOS Next中,通过CameraManager动态配置与切换相机预览/拍照分辨率,并保证预览画面不变形,核心在于正确管理CameraOutputCapability、独立配置预览与拍照的Profile,并应用合适的预览缩放策略。以下是关键步骤和代码要点:

1. 获取相机设备与输出能力

首先获取CameraManager实例和相机设备列表,然后通过CameraManager的getSupportedOutputCapability()方法获取指定相机的输出能力对象CameraOutputCapability。此对象包含了该设备支持的所有流组合、分辨率等信息。

import camera from '@ohos.multimedia.camera';
// ... 获取cameraManager
let cameraDevice: camera.CameraDevice = ...; // 获取目标相机设备
let outputCapability: camera.CameraOutputCapability = cameraManager.getSupportedOutputCapability(cameraDevice);

2. 动态选择与配置分辨率

  • 预览流:从outputCapability.previewProfiles中获取支持的预览配置列表(Profile对象数组)。每个Profile包含尺寸、格式等信息。根据你的UI需求(如预览视图宽高比)和性能考虑,从中筛选出合适的分辨率列表供用户选择。
  • 拍照流:类似地,从outputCapability.photoProfiles中获取支持的拍照配置列表。拍照分辨率的选择可以独立于预览分辨率。

切换逻辑:当用户选择新的分辨率时,你需要基于选定的分辨率,从对应的Profiles列表中查找匹配的Profile对象。然后,在创建或重新配置相机流时使用它。

3. 创建并配置相机流

  • 预览流:使用cameraManager.createPreviewOutput()方法,传入为预览选定的Profile对象以及预览的Surface(例如从<XComponent>获取的SurfaceId)。这将创建PreviewOutput对象。
  • 拍照流:使用cameraManager.createPhotoOutput()方法,传入为拍照选定的Profile对象,创建PhotoOutput对象。

注意CameraOutputCapability中也提供了推荐的流组合(supportedOutputCapability.sessionConfigs),但如果你需要动态切换分辨率,通常需要手动管理PreviewOutputPhotoOutput的创建与更新。

4. 保证预览不变形(关键步骤)

预览拉伸或变形通常是因为预览流的宽高比与预览视图(如<XComponent>)的宽高比不匹配。HarmonyOS Next的相机框架提供了PreviewOutput缩放与裁剪功能来解决此问题。

  • 计算与设置缩放区域:通过PreviewOutputsetCropRegion()方法,你可以指定一个相对于传感器有效像素区域的矩形区域作为实际的预览内容源。核心步骤是:
    1. 根据预览视图的宽高比和预览流Profile分辨率,计算出需要从传感器区域中裁剪出的矩形区域,确保此区域的宽高比与视图一致。
    2. 将此矩形区域(Region对象,包含x, y, width, height,坐标原点在传感器区域左上角)通过setCropRegion()方法设置给PreviewOutput
// 假设 previewOutput 是你的 PreviewOutput 实例
// 假设 previewViewRatio 是预览视图的宽高比 (width/height)
// 假设 sensorActiveArraySize 是相机传感器的有效像素区域(可从 CameraOutputCapability 或设备信息获取)
let sensorWidth: number = sensorActiveArraySize.width;
let sensorHeight: number = sensorActiveArraySize.height;
let sensorRatio: number = sensorWidth / sensorHeight;

let cropRegion: camera.Region;
if (previewViewRatio > sensorRatio) {
    // 视图更宽,以传感器宽度为基准,计算裁剪高度
    let cropHeight: number = sensorWidth / previewViewRatio;
    cropRegion = {
        x: 0,
        y: Math.round((sensorHeight - cropHeight) / 2),
        width: sensorWidth,
        height: Math.round(cropHeight)
    };
} else {
    // 视图更高或比例相同,以传感器高度为基准,计算裁剪宽度
    let cropWidth: number = sensorHeight * previewViewRatio;
    cropRegion = {
        x: Math.round((sensorWidth - cropWidth) / 2),
        y: 0,
        width: Math.round(cropWidth),
        height: sensorHeight
    };
}
previewOutput.setCropRegion(cropRegion);

这样,相机框架会自动将裁剪区域的图像内容缩放至预览视图大小,从而保证预览画面不变形。

5. 会话配置与启动

将配置好的PreviewOutputPhotoOutput等加入CaptureSession,配置会话(session.beginConfig()session.addOutput()session.commitConfig()),最后启动会话(session.start())。当需要切换分辨率时,一种可行的方法是:

  • 停止当前会话 (session.stop())。
  • 释放旧的PreviewOutput/PhotoOutput(如需要)。
  • 按照新的分辨率重新创建PreviewOutput/PhotoOutput,并重新计算和设置裁剪区域。
  • 重新配置并启动会话。

总结:动态切换分辨率的重点在于根据用户选择,从CameraOutputCapability中获取对应的Profile并创建新的输出流。保证预览不变形的核心在于利用PreviewOutput.setCropRegion(),根据预览视图的宽高比和传感器有效区域,计算出正确的裁剪区域,使输出图像的宽高比与视图保持一致。

回到顶部