鸿蒙App开发--压花集怎么拍照记录?HarmonyOS相机拍照实战
·
压花标本怎么拍照记录?HarmonyOS相机拍照实战
如果你对压花艺术感兴趣,可以去鸿蒙应用市场搜一下**「压花集」**,下载下来体验体验。拍下花朵标本的照片,记录压制过程,建立自己的压花素材库。体验完了再回来看这篇文章,你会更清楚相机拍照功能是怎么实现的。
写在前面
大家好,我是一名写了十多年Web前端的老兵。这篇文章围绕"压花集"的标本拍照功能,讲解HarmonyOS的相机API使用。
这篇文章聊什么
压花集的标本拍照功能,核心要解决:
- 相机调用:使用系统相机拍照
- 照片保存:保存到应用目录
- 标本信息:记录花材名称、采集日期等
- 标本管理:管理所有标本照片
第一步:设计标本数据结构
// 压花标本
interface PressedFlower {
id: string;
name: string; // 花材名称
photoUri: string; // 照片路径
flowerType: string; // 花材类型
color: string; // 颜色
season: string; // 采集季节
pressMethod: string; // 压制方法
pressDays: number; // 压制天数
collectDate: string; // 采集日期
pressDate: string; // 开始压制日期
completeDate: string; // 完成日期
status: string; // 状态
notes: string;
createdAt: string;
}
// 花材类型
const FLOWER_TYPES = [
{ id: 'rose', name: '玫瑰', color: '#e11d48', season: '春', pressDays: 7 },
{ id: 'lavender', name: '薰衣草', color: '#8b5cf6', season: '夏', pressDays: 5 },
{ id: 'daisy', name: '雏菊', color: '#fbbf24', season: '春', pressDays: 4 },
{ id: 'hydrangea', name: '绣球花', color: '#3b82f6', season: '夏', pressDays: 8 },
{ id: 'cherry_blossom', name: '樱花', color: '#f9a8d4', season: '春', pressDays: 3 },
{ id: 'maple', name: '枫叶', color: '#dc2626', season: '秋', pressDays: 6 },
{ id: 'ginkgo', name: '银杏叶', color: '#eab308', season: '秋', pressDays: 5 },
{ id: 'fern', name: '蕨类', color: '#22c55e', season: '夏', pressDays: 4 },
{ id: 'baby_breath', name: '满天星', color: '#e5e7eb', season: '四季', pressDays: 3 },
{ id: 'sunflower', name: '向日葵', color: '#f97316', season: '夏', pressDays: 10 },
];
// 状态
const WORK_STATUS = [
{ id: 'collecting', name: '采集中', color: '#22c55e' },
{ id: 'pressing', name: '压制中', color: '#3b82f6' },
{ id: 'completed', name: '已完成', color: '#ec4899' },
];
第二步:实现相机拍照
import { camera } from '@kit.CameraKit';
import { fileIo } from '@kit.CoreFileKit';
@Entry
@Component
struct FlowerCameraPage {
@State isCameraReady: boolean = false
@State capturedPhoto: string = ''
@State isPreviewMode: boolean = true
private cameraManager: camera.CameraManager | null = null
private captureSession: camera.CaptureSession | null = null
private photoOutput: camera.PhotoOutput | null = null
async aboutToAppear() {
await this.initCamera()
}
aboutToDisappear() {
this.releaseCamera()
}
async initCamera() {
try {
this.cameraManager = camera.getCameraManager(getContext())
const cameras = this.cameraManager.getSupportedCameras()
if (cameras.length === 0) return
const configs = this.cameraManager.getSupportedOutputCapability(cameras[0])
if (configs.length === 0) return
const profile = configs[0]
const previewOutput = this.cameraManager.createPreviewOutput(
profile.previewProfiles[0], 'camera_preview'
)
this.photoOutput = this.cameraManager.createPhotoOutput(profile.photoProfiles[0])
this.captureSession = this.cameraManager.createCaptureSession()
this.captureSession.beginConfig()
const cameraInput = this.cameraManager.createCameraInput(cameras[0])
cameraInput.open()
this.captureSession.addInput(cameraInput)
this.captureSession.addOutput(previewOutput)
this.captureSession.addOutput(this.photoOutput)
await this.captureSession.commitConfig()
await this.captureSession.start()
this.isCameraReady = true
} catch (err) {
console.error(`初始化相机失败: ${err}`)
}
}
async takePhoto() {
if (!this.photoOutput) return
try {
const photo = await this.photoOutput.capture()
photo.on('photoAvailable', async (err, photoResult) => {
if (err) return
const mainImage = photoResult.main
const buffer = await mainImage.readPixelsBuffer()
const fileName = `flower_${Date.now()}.jpg`
const filePath = `${getContext().filesDir}/${fileName}`
const file = fileIo.openSync(filePath, fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY)
fileIo.writeSync(file.fd, buffer)
fileIo.closeSync(file)
this.capturedPhoto = filePath
this.isPreviewMode = false
})
} catch (err) {
console.error(`拍照失败: ${err}`)
}
}
private releaseCamera() {
if (this.captureSession) {
this.captureSession.release()
this.captureSession = null
}
}
build() {
Column() {
if (this.isPreviewMode) {
XComponent({ id: 'camera_preview', type: XComponentType.SURFACE, libraryname: '' })
.width('100%')
.aspectRatio(4 / 3)
.backgroundColor('#000')
.borderRadius(12)
Button('拍照')
.width(80)
.height(80)
.backgroundColor('#ec4899')
.borderRadius(40)
.margin({ top: 20 })
.enabled(this.isCameraReady)
.onClick(() => this.takePhoto())
} else {
Image(this.capturedPhoto)
.width('100%')
.aspectRatio(4 / 3)
.objectFit(ImageFit.Cover)
.borderRadius(12)
Row() {
Button('重拍')
.layoutWeight(1)
.height(48)
.backgroundColor('#f3f4f6')
.fontColor('#374151')
.borderRadius(12)
.onClick(() => { this.isPreviewMode = true })
Button('使用照片')
.layoutWeight(1)
.height(48)
.backgroundColor('#ec4899')
.borderRadius(12)
.margin({ left: 12 })
}
.width('100%')
.margin({ top: 20 })
}
}
.padding(16)
}
}
第三步:保存标本信息
import { preferences } from '@kit.ArkData';
async function addFlower(context: Context, flower: PressedFlower): Promise<boolean> {
const flowers = await getItem<PressedFlower[]>(context, 'flowers', []);
const newFlower: PressedFlower = {
...flower,
id: `flower_${Date.now()}`,
createdAt: new Date().toISOString().slice(0, 10)
};
flowers.push(newFlower);
return await setItem(context, 'flowers', flowers);
}
async function getFlowers(context: Context): Promise<PressedFlower[]> {
return await getItem<PressedFlower[]>(context, 'flowers', []);
}
async function updateFlowerStatus(context: Context, id: string, status: string): Promise<boolean> {
const flowers = await getItem<PressedFlower[]>(context, 'flowers', []);
const index = flowers.findIndex(f => f.id === id);
if (index === -1) return false;
flowers[index].status = status;
if (status === 'completed') {
flowers[index].completeDate = new Date().toISOString().slice(0, 10);
}
return await setItem(context, 'flowers', flowers);
}
第四步:常见问题
4.1 相机权限
问题:调用相机报错。
解决:在module.json5里声明相机权限。
4.2 照片质量
问题:照片不够清晰。
解决:调整相机分辨率设置。
总结
这篇文章围绕"压花集"的标本拍照功能,讲解了:
相机使用
- @ohos.camera API调用
- 照片保存到应用目录
数据管理
- 标本信息存储
- 状态追踪
如果你对"压花集"感兴趣,欢迎去鸿蒙应用市场搜索下载体验。
更多推荐



所有评论(0)