文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

如何调用设备摄像头进行拍照、预览并将拍摄结果保存在媒体库中(Camera)

2024-11-30 03:33

关注

想了解更多关于开源的内容,请访问:

51CTO 开源基础软件社区

https://ost.51cto.com

场景说明

调用设备摄像头进行拍照、预览是许多应用开发过程中都需要的功能。在拍照完成时显示照片预览图可以确认拍摄的照片是否达到预期,本例将为大家介绍如何实现上述功能。

效果呈现

本例效果如下:

拍照

预览

运行环境

本例基于以下环境开发,开发者也可以基于其他适配的版本进行开发。

实现思路

本例使用@ohos.multimedia.camera接口实现相机示例的主要功能:拍照、预览;

开发步骤

申请所需权限:
在model.json5中添加以下配置:

"requestPermissions": [
      {
        "name": "ohos.permission.CAMERA"//允许应用使用相机拍摄照片和录制视频
      },
      {
        "name": "ohos.permission.MICROPHONE"//允许应用使用麦克风
      },
      {
        "name": "ohos.permission.MEDIA_LOCATION"//允许应用访问用户媒体文件中的地理位置信息
      },
      {
        "name": "ohos.permission.WRITE_MEDIA"//允许应用读写用户外部存储中的媒体文件信息
      },
      {
        "name": "ohos.permission.READ_MEDIA"//允许应用读取用户外部存储中的媒体文件信息
      }
    ]

创建绘制组件XComponent以输出摄像头获取的画面,其绑定的onload方法中设定了画幅的大小。

build() {
    Column() {
      Title()
        .visibility(this.isTitleShow ? Visibility.Visible : Visibility.None) 
      Stack({ alignContent: Alignment.Bottom }) {
        Stack({ alignContent: Alignment.TopStart }) {
          XComponent({
            id: 'componentId',
            type: 'surface',
            controller: this.mXComponentController  //将控制器绑定至XComponent组件
          })
            .onLoad(() => {
              this.mXComponentController.setXComponentSurfaceSize({ surfaceWidth: 640, surfaceHeight: 480 });//设置surface大小
              this.surfaceId = this.mXComponentController.getXComponentSurfaceId();
              this.currentModel = CameraMode.modePhoto; 
              this.cameraModel.initCamera(this.surfaceId); //调用model/cameraModel.ts初始化相机功能
            })
            .width('100%')
            .height('100%')
            .margin({ bottom: 152 })
            Column() {
        }
        .width('97%')
        .height('100%')

初始化相机功能initCamera方法通过创建相机管理器实例cameraMgr来创建画面输出对象previewOutput。cameraMgr再通过创建CaptureSession实例来配置会话,完成相机功能的准备工作。

import image from '@ohos.multimedia.image';//自@ohos.multimedia.image引入image,提供图片处理效果
...
private receiver: image.ImageReceiver = undefined;//图像接收类,用于获取组件surface id,接收最新的图片和读取下一张图片
...
constructor() {
    this.mediaModel = MediaModel.getMediaInstance();//通过调用model/MediaModel.ets中的方法创建mediaInstance类mediaModel
    //创建ImageReceiver实例receiver
    this.receiver = image.createImageReceiver(
      cameraWH.width,
      cameraWH.height,
      FOUR,
      EIGHT
    );
    //接收图片时注册回调
    this.receiver.on('imageArrival', () => {
       //从ImageReceiver读取下一张图片
      this.receiver.readNextImage((err, image) => {
        if (err || image === undefined) {
          return;
        }
        //根据图像的组件类型从图像中获取组件缓存 
        image.getComponent(FOUR, (errMsg, img) => {
          if (errMsg || img === undefined) {
            return;
          }
          let buffer = new ArrayBuffer(FOUR_THOUSAND_AND_SIXTY_NINE);
          if (img.byteBuffer) {
            buffer = img.byteBuffer;
          } 
          this.saveImage(buffer, image);
        });
      });
    });
  }


async initCamera(surfaceId: string): Promise {
    ...
    try {
      this.cameraMgr = camera.getCameraManager(globalThis.cameraContext);//获取相机管理器实例
    } 
    this.camerasArray = this.cameraMgr.getSupportedCameras();//获取支持指定的相机设备对象
    if (this.camerasArray.length === 0) {
      return;
    }
    let mCamera = this.camerasArray[0];
    this.cameraInput = this.cameraMgr.createCameraInput(mCamera);
    this.cameraInput.open();
    this.capability = this.cameraMgr.getSupportedOutputCapability(mCamera);//查询相机设备支持的输出能力
    let previewProfile = this.capability.previewProfiles[0];
	//通过相机管理器创建预览输出对象
    this.previewOutput = this.cameraMgr.createPreviewOutput(
      previewProfile,												
      surfaceId												//surfaceId从XComponent组件获取
    );
    let rSurfaceId = await this.receiver.getReceivingSurfaceId();//获取一个surface id供其他组件使用
    let photoProfile = this.capability.photoProfiles[0];
	//通过相机管理器创建照片输出对象
    this.photoOutPut = this.cameraMgr.createPhotoOutput(
      photoProfile,
      rSurfaceId										//rSurfaceId通过构造函数中定义的图像接收类receiver获取
    );
    this.capSession = this.cameraMgr.createCaptureSession();//创建CaptureSession实例
    this.capSession.beginConfig();//开始配置会话
    this.capSession.addInput(this.cameraInput);//将cameraInput加入会话
    this.capSession.addOutput(this.previewOutput);//将预览输出加入会话
    this.capSession.addOutput(this.photoOutPut);//将照片输出加入会话
    await this.capSession.commitConfig();//提交配置信息
    await this.capSession.start();//开始输出
  }

点击按钮进行拍照,拍照按钮通过Image组件呈现,其绑定的onClick方法调用takePicture方法开始拍照。

Image(this.getCameraIcon())
              .size({ width: 64, height: 64 })
              .margin({ left: 10 })
              .id('camera')
              .onClick(() => {
                if (this.currentModel === CameraMode.modePhoto) {
                  prompt.showToast({ message: '拍照中...', duration: 200 });
                  this.cameraModel.takePicture();//调用model/cameraModel.takePicture()开始拍照
                } 
              })

拍照功能具体实现:

拍照:

async takePicture(): Promise {
    //设置拍照相关参数
    let photoSettings = {
      rotation: this.imageRotation,
      quality: camera.QualityLevel.QUALITY_LEVEL_MEDIUM,
      location: {
        // 位置信息,经纬度
        latitude: 12.9698,
        longitude: 77.75,
        altitude: 1000,
      },
      mirror: false,
    };
    await this.photoOutPut.capture(photoSettings);
    AppStorage.Set('isRefresh', true);
  }

保存图片:
saveImage方法使用MediaModel中的createAndGetUri方法创建Image类型资源,将拍摄到的照片写入到这个资源中去。

//model/MediaModel.ts中定义的负责保存图片的相关方法
async createAndGetUri(mediaType: mediaLibrary.MediaType): Promise {
    let dateTimeUtil: DateTimeUtil = new DateTimeUtil();
    let info: FileInfo = this.getInfoFromMediaType(mediaType);
    let name: string = `${dateTimeUtil.getDate()}_${dateTimeUtil.getTime()}`;//获取当前时间
    let displayName: string = `${info.prefix}${name}${info.suffix}`;
	//获取公共目录路径。
    let publicPath: string = await this.mediaLibraryTest.getPublicDirectory(
      info.directory
    );//通过引用自@ohos.multimedia.mediaLibrary的mediaLibraryTest类创建媒体资源,其中定义了媒体类型、名称、路径。
    let fileAsset: mediaLibrary.FileAsset = await this.mediaLibraryTest.createAsset(
      mediaType,//根据传入函数createAndGetUri的mediaType参数决定创建什么类型的媒体资源
      displayName,
      publicPath
    );
    return fileAsset;
  }
  async getFdPath(fileAsset: mediaLibrary.FileAsset): Promise {
    let fd: number = await fileAsset.open('Rw');//打开当前文件
    return fd;
  }
...

async saveImage(buffer: ArrayBuffer, img: image.Image): Promise {
    this.fileAsset = await this.mediaModel.createAndGetUri(mediaLibrary.MediaType.IMAGE);
	//通过调用MediaModel中的方法创建Image类型资源
    this.photoPath = this.fileAsset.uri;
    this.fd = await this.mediaModel.getFdPath(this.fileAsset);
    await fileIo.write(this.fd, buffer);//将拍摄的照片写入到Mediamodel传回的资源中去
    await this.fileAsset.close(this.fd);//释放open函数
    await img.release();
    if (this.takePictureHandle) {
      this.takePictureHandle(this.photoPath);
    }
  }

想了解更多关于开源的内容,请访问:

51CTO 开源基础软件社区

https://ost.51cto.com

来源:51CTO 开源基础软件社区内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯