压花标本怎么拍照记录?HarmonyOS相机拍照实战

如果你对压花艺术感兴趣,可以去鸿蒙应用市场搜一下**「压花集」**,下载下来体验体验。拍下花朵标本的照片,记录压制过程,建立自己的压花素材库。体验完了再回来看这篇文章,你会更清楚相机拍照功能是怎么实现的。


写在前面

大家好,我是一名写了十多年Web前端的老兵。这篇文章围绕"压花集"的标本拍照功能,讲解HarmonyOS的相机API使用。


这篇文章聊什么

压花集的标本拍照功能,核心要解决:

  1. 相机调用:使用系统相机拍照
  2. 照片保存:保存到应用目录
  3. 标本信息:记录花材名称、采集日期等
  4. 标本管理:管理所有标本照片

第一步:设计标本数据结构

// 压花标本
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调用
  • 照片保存到应用目录

数据管理

  • 标本信息存储
  • 状态追踪

如果你对"压花集"感兴趣,欢迎去鸿蒙应用市场搜索下载体验。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐