第43篇|高质量拍摄参数:长边、面积、质量等级如何取舍
高质量拍摄不是把所有参数无限拉满。移动端相机项目要同时考虑画质、合成耗时、内存占用、落盘速度和后续上传。双镜记忆相机的做法是:拍摄时使用高质量等级,合成和输出时控制长边与面积。
这一篇从项目里的常量开始看,理解为什么QUALITY_LEVEL_HIGH、preferredCaptureLongSide、preferredCaptureArea和合成服务里的 JPEG 质量要共同工作。
这一篇继续围绕 21 天「智能相机开发实战」训练营展开。内容只使用当前项目里的 ArkTS、服务层代码和真实页面截图来讲,不把封面图放进正文。阅读时可以先看截图理解用户侧效果,再顺着函数名回到工程定位实现。
本篇目标
- 理解拍摄质量和输出尺寸是两类不同问题。
- 掌握 PhotoCaptureSetting 如何使用统一质量等级。
- 读懂合成服务如何限制输出长边。
- 形成移动端画质、性能和文件体积之间的取舍意识。
对应源码位置
entry/src/main/ets/pages/Index.etsentry/src/main/ets/services/DualPhotoComposerService.ets
一、高质量首先是稳定基线,不是盲目大图
项目在页面类里定义了拍摄质量等级和偏好的输出规模。QUALITY_LEVEL_HIGH保证捕获质量,preferredCaptureLongSide和preferredCaptureArea用来控制后续处理的尺寸边界。
这类常量最好集中在类级配置中,而不是散落在不同拍摄函数里。集中后,调参时能看到一组相互关联的质量策略。
图1 画质参数从拍摄到合成再到相册体验的流向
二、质量配置集中定义,便于统一调参
captureQualityLevel决定拍摄设置的质量基线。两个 preferred 常量则表达项目对可处理图片尺寸的偏好。它们不是 UI 文案,而是工程策略:既要让照片清晰,又要避免合成服务处理过大的像素数据。
当训练营学员在真机上发现合成慢、内存高或上传慢时,可以先回到这一组常量,判断是拍摄输出过大,还是合成阶段需要额外压缩。
图2 拍摄质量、目标长边和目标面积作为类级配置
private readonly captureQualityLevel: camera.QualityLevel = camera.QualityLevel.QUALITY_LEVEL_HIGH; private readonly preferredCaptureLongSide: number = 2560; private readonly preferredCaptureArea: number = 2560 * 1920; private readonly cloudLoginButtonController: loginComponentManager.LoginWithHuaweiIDButtonController =不要把“质量高”简单理解成“文件越大越好”。真正能上线的相机体验,需要在清晰度和稳定性之间找到平衡点。
三、双拍和单拍共用同一个质量等级
无论是后摄还是前摄,双拍路径都使用同一个captureQualityLevel。这能保证同一组作品里两张素材的质量策略一致,后续合成时不会出现一张明显压缩、一张过大的不平衡情况。
单拍路径也复用同一个质量等级。统一设置的好处是后续调整质量时不需要分别修改三条路径,减少漏改。
图3 双拍和单拍都使用同一个 captureQualityLevel
const backCaptureSetting: camera.PhotoCaptureSetting = { quality: this.captureQualityLevel, rotation: camera.ImageRotation.ROTATION_0, mirror: false }; const frontCaptureSetting: camera.PhotoCaptureSetting = { quality: this.captureQualityLevel, rotation: camera.ImageRotation.ROTATION_0, mirror: true }; try {如果要针对前摄单独降低质量,也应该增加明确的策略函数,而不是在某个 captureSetting 里临时写死。
四、合成输出要限制长边,保护内存和速度
DualPhotoComposerService会根据源图尺寸计算输出尺寸。如果原图长边没有超过最大值,就保留尺寸;超过后按比例缩放。这样既保留画面比例,又控制像素总量。
双镜合成涉及解码、拷贝像素、绘制圆形前摄小窗、重新编码 JPEG。每一步都吃内存和 CPU,所以输出尺寸控制是稳定体验的一部分。
图4 DualPhotoComposerService 统一裁剪合成输出尺寸
private static normalizeOutputSize(sourceSize: ComposeSize): ComposeSize { if (sourceSize.width <= 0 || sourceSize.height <= 0) { return { width: DualPhotoComposerService.DUAL_OUTPUT_WIDTH, height: DualPhotoComposerService.DUAL_OUTPUT_HEIGHT }; } const sourceLongSide = Math.max(sourceSize.width, sourceSize.height); if (sourceLongSide <= DualPhotoComposerService.MAX_OUTPUT_LONG_SIDE) { return { width: DualPhotoComposerService.toEven(sourceSize.width), height: DualPhotoComposerService.toEven(sourceSize.height) }; } const scale = DualPhotoComposerService.MAX_OUTPUT_LONG_SIDE / sourceLongSide; return { width: DualPhotoComposerService.toEven(Math.round(sourceSize.width * scale)), height: DualPhotoComposerService.toEven(Math.round(sourceSize.height * scale)) };画质策略最终要用真机验证。建议记录同一场景下的文件大小、合成耗时和预览流畅度,再决定是否继续上调长边。
工程检查清单
- 拍摄质量等级集中定义,双拍和单拍复用。
- 输出长边和面积限制服务于稳定性,不只是节省空间。
- 合成服务负责输出尺寸归一化,页面层不处理像素细节。
- JPEG 质量、输出尺寸和上传速度要一起评估。
- 调参后用真机验证文件大小和合成耗时。
今日练习
- 把
preferredCaptureLongSide从 2560 改成 1920,推测合成速度和清晰度会怎样变化。 - 阅读
DualPhotoComposerService.JPEG_QUALITY,思考它和QualityLevel的区别。 - 记录一次双拍输出文件大小,作为后续调参的基准。
训练营后面的内容会继续按“真实页面效果 → 源码定位 → 状态闭环 → 可验证结果”的节奏推进。每一篇都尽量让你能拿着代码直接回到项目里复现,而不是只停留在概念说明。