摄日的相机专业模式:Camera API与参数控制
如果你是摄影爱好者,推荐去鸿蒙应用市场搜一下**「摄日」**,下载体验体验。每日摄影挑战、完整参数记录、构图技法参考,一套走下来对摄影技巧的提升会有很大帮助。体验完再回来看这篇文章,你会更清楚相机专业模式和参数控制背后是怎么实现的。
写在前面
大家好,我是一名写了十多年Web前端的老兵。从jQuery时代一路走到React/Vue,CSS3动画、requestAnimationFrame、Web Animation API这些都算是看家本领。去年开始转战鸿蒙生态,用ArkTS开发App,这一路踩了不少坑,也积累了不少心得。
很多人觉得"前端转鸿蒙"应该很容易——都是写UI嘛,组件化、状态管理、生命周期,概念都差不多。但真正上手之后你会发现,相似的地方让你觉得亲切,不同的地方让你抓狂。
比如:
- 相机控制:Web里用
getUserMedia,鸿蒙里用@ohos.camera,API体系完全不同。 - 参数控制:Web里相机参数有限,鸿蒙里可以控制光圈、快门、ISO、白平衡等专业参数。
- 数据存储:Web的
localStorage到了ArkTS变成了@ohos.data.preferences。
接下来这篇文章,我会用"摄日"的实际开发经历,带你看看鸿蒙的相机专业模式怎么实现——从相机参数控制到拍摄模式选择。
这篇文章聊什么
摄日这个App,核心要解决两个问题:
- 相机专业模式:控制光圈、快门、ISO、白平衡等参数
- 拍摄记录:记录每次拍摄的完整参数
对应到HarmonyOS的API,主要涉及:
@ohos.camera— 相机专业模式控制@ohos.data.preferences— 拍摄记录存储
第一步:拍摄模式定义
// 拍摄模式
const SHOOTING_MODES = [
{ id: 'auto', name: '自动', desc: '全自动拍摄' },
{ id: 'aperture', name: '光圈优先', desc: '控制景深' },
{ id: 'shutter', name: '快门优先', desc: '控制运动模糊' },
{ id: 'manual', name: '手动', desc: '完全手动控制' },
{ id: 'bulb', name: 'B门', desc: '长时间曝光' }
];
// 白平衡预设
const WHITE_BALANCE = [
{ id: 'auto', name: '自动' },
{ id: 'daylight', name: '日光', temp: 5500 },
{ id: 'cloudy', name: '阴天', temp: 6500 },
{ id: 'shade', name: '阴影', temp: 7500 },
{ id: 'tungsten', name: '钨丝灯', temp: 3200 },
{ id: 'fluorescent', name: '荧光灯', temp: 4000 },
{ id: 'flash', name: '闪光灯', temp: 5500 }
];
// 拍摄参数
interface ShootingParams {
aperture: string;
shutterSpeed: string;
iso: number;
whiteBalance: string;
exposureCompensation: number; // 曝光补偿(EV)
focusMode: string; // auto/manual
meteringMode: string; // matrix/center/spot
}
第二步:相机参数控制
鸿蒙相机API支持的参数控制:
import { camera } from '@kit.CameraKit';
// 设置相机参数
async function setCameraParams(
captureSession: camera.CaptureSession,
params: ShootingParams
) {
// 设置曝光模式
const exposureMode = params.shutterSpeed === 'auto'
? camera.ExposureMode.EXPOSURE_MODE_AUTO
: camera.ExposureMode.EXPOSURE_MODE_MANUAL;
// 设置ISO
if (params.iso > 0) {
// 通过PhotoCaptureSetting设置
}
// 设置白平衡
const wbMode = params.whiteBalance === 'auto'
? camera.WhiteBalanceMode.AWB_MODE_AUTO
: camera.WhiteBalanceMode.AWB_MODE_DAYLIGHT;
}
第三步:拍摄记录页面
@Entry
@Component
struct ShotRecordPage {
@State mode: string = 'auto'
@State aperture: string = 'f/5.6'
@State shutterSpeed: string = '1/125'
@State iso: number = 400
@State whiteBalance: string = 'auto'
@State evCompensation: number = 0
@State notes: string = ''
private apertures = ['f/1.4', 'f/2', 'f/2.8', 'f/4', 'f/5.6', 'f/8', 'f/11', 'f/16']
private shutterSpeeds = ['30"', '15"', '8"', '4"', '2"', '1"', '1/2', '1/4',
'1/8', '1/15', '1/30', '1/60', '1/125', '1/250', '1/500', '1/1000']
build() {
Column() {
// 拍摄模式选择
Flex({ wrap: FlexWrap.Wrap }) {
ForEach(SHOOTING_MODES, (m) => {
Text(m.name)
.fontSize(13)
.padding(8)
.margin(4)
.borderRadius(8)
.backgroundColor(this.mode === m.id ? '#10B981' : '#374151')
.fontColor(this.mode === m.id ? '#FFF' : '#D1D5DB')
.onClick(() => { this.mode = m.id })
})
}
.margin({ bottom: 16 })
// 光圈选择
Text('光圈')
.fontSize(14)
.fontColor('#9CA3AF')
.margin({ bottom: 8 })
Flex({ wrap: FlexWrap.Wrap }) {
ForEach(this.apertures, (ap: string) => {
Text(ap)
.fontSize(13)
.padding(8)
.margin(4)
.borderRadius(8)
.backgroundColor(this.aperture === ap ? '#F59E0B' : '#374151')
.fontColor(this.aperture === ap ? '#FFF' : '#D1D5DB')
.onClick(() => { this.aperture = ap })
})
}
.margin({ bottom: 16 })
// 快门速度选择
Text('快门速度')
.fontSize(14)
.fontColor('#9CA3AF')
.margin({ bottom: 8 })
Flex({ wrap: FlexWrap.Wrap }) {
ForEach(this.shutterSpeeds, (speed: string) => {
Text(speed)
.fontSize(13)
.padding(8)
.margin(4)
.borderRadius(8)
.backgroundColor(this.shutterSpeed === speed ? '#3B82F6' : '#374151')
.fontColor(this.shutterSpeed === speed ? '#FFF' : '#D1D5DB')
.onClick(() => { this.shutterSpeed = speed })
})
}
.margin({ bottom: 16 })
// ISO选择
Row() {
Text('ISO')
.fontSize(14)
.fontColor('#9CA3AF')
Slider({ value: this.iso, min: 50, max: 6400, step: 1 })
.onChange((v: number) => {
const commonISOs = [50, 100, 200, 400, 800, 1600, 3200, 6400]
this.iso = commonISOs.reduce((prev, curr) =>
Math.abs(curr - v) < Math.abs(prev - v) ? curr : prev
)
})
.layoutWeight(1)
Text(`${this.iso}`)
.fontSize(16)
.fontWeight(FontWeight.Bold)
.width(50)
.textAlign(TextAlign.Center)
}
.width('100%')
.margin({ bottom: 16 })
// 曝光补偿
Row() {
Text('曝光补偿')
.fontSize(14)
.fontColor('#9CA3AF')
Slider({ value: this.evCompensation, min: -3, max: 3, step: 0.3 })
.onChange((v: number) => { this.evCompensation = Math.round(v * 10) / 10 })
.layoutWeight(1)
Text(`${this.evCompensation > 0 ? '+' : ''}${this.evCompensation}EV`)
.fontSize(14)
.fontWeight(FontWeight.Bold)
.width(60)
}
.width('100%')
.margin({ bottom: 16 })
Button('保存拍摄记录')
.onClick(() => this.saveRecord())
.width('100%')
.backgroundColor('#10B981')
}
.width('100%')
.height('100%')
.padding(16)
.backgroundColor('#111827')
}
async saveRecord() {
const record = {
id: `shot_${Date.now()}`,
mode: this.mode,
aperture: this.aperture,
shutterSpeed: this.shutterSpeed,
iso: this.iso,
whiteBalance: this.whiteBalance,
evCompensation: this.evCompensation,
notes: this.notes,
timestamp: Date.now()
};
const store = await preferences.getPreferences(getContext(), 'sheri_data');
let records = JSON.parse(await store.get('shots', '[]') as string);
records.push(record);
await store.set('shots', JSON.stringify(records));
await store.flush();
}
}
第四步:12种构图技法
const COMPOSITION_TECHNIQUES = [
{ id: 'rule_of_thirds', name: '三分法', desc: '将画面分成3x3网格,主体放在交叉点' },
{ id: 'center', name: '居中构图', desc: '主体放在画面正中央' },
{ id: 'symmetry', name: '对称构图', desc: '利用对称元素创造平衡感' },
{ id: 'leading_lines', name: '引导线', desc: '用线条引导视线到主体' },
{ id: 'frame', name: '框架构图', desc: '用前景元素框住主体' },
{ id: 'diagonal', name: '对角线', desc: '利用对角线创造动感' },
{ id: 'triangle', name: '三角形', desc: '三角形构图创造稳定感' },
{ id: 'golden_ratio', name: '黄金比例', desc: '1.618:1的完美比例' },
{ id: 'negative_space', name: '留白', desc: '大量空白突出主体' },
{ id: 'fill_frame', name: '填满画面', desc: '主体占满整个画面' },
{ id: 'pattern', name: '重复图案', desc: '利用重复元素创造节奏' },
{ id: 'break_pattern', name: '打破规律', desc: '在重复中加入变化' }
];
总结
这篇文章围绕"摄日"的相机专业模式,讲解了三个核心主题:
- 拍摄模式:自动、光圈优先、快门优先、手动、B门五种模式
- 参数控制:光圈、快门、ISO、白平衡、曝光补偿的UI选择器
- 构图技法:12种常用构图方法的参考
相机专业模式的核心是参数之间的关系——光圈控制景深,快门控制运动模糊,ISO控制噪点。理解这个"曝光三角",就能拍出更好的照片。
如果你也是摄影爱好者,希望这篇文章能帮你理解摄日背后的相机控制逻辑。去鸿蒙应用市场下载体验一下吧,有问题欢迎交流。