鸿蒙 ohos ArkTS - 调用摄像头拍照、缓存图片、展示图片

638 阅读1分钟
  • 当前用的前置摄像头
  • aboutToAppear 中实现了权限请求,但是申请权限理应放在页面跳转之前
  • 研究了大半天,不多废话
import { camera } from '@kit.CameraKit';
import { image } from '@kit.ImageKit';
import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { fileIo as fs } from '@kit.CoreFileKit';
import { display } from '@kit.ArkUI';

@Entry
@Component
struct Index {
  @State desStr: string = ""
  @State photoUriMedia: string = ""
  @State imgUrl: string = ""
  private mXComponentController = new XComponentController()
  private cameraManager: camera.CameraManager | undefined = undefined
  private camerasAll: Array<camera.CameraDevice> | undefined = undefined
  private camera: camera.CameraDevice | undefined = undefined
  private mReceiver: image.ImageReceiver | undefined = undefined
  private cameraInput: camera.CameraInput | undefined = undefined
  private previewOutput: camera.PreviewOutput | undefined = undefined
  private mSurfaceId: string | undefined = undefined
  private photoOutput: camera.PhotoOutput | undefined = undefined
  private photoSession: camera.PhotoSession | undefined = undefined
  private surfaceId: string | undefined = undefined
  private context: common.UIAbilityContext | undefined = undefined
  private screenWidth: number = 0;
  private screenHeight: number = 0;

  aboutToAppear() {
    this.screenWidth = display.getDefaultDisplaySync().width
    this.screenHeight = display.getDefaultDisplaySync().height
    this.context = getContext(this) as common.UIAbilityContext
    this.requestPermissions(["ohos.permission.CAMERA", "ohos.permission.MICROPHONE", "ohos.permission.MEDIA_LOCATION",
      "ohos.permission.WRITE_MEDIA", "ohos.permission.READ_MEDIA"], this.context!);
  }

  async initCamera(surfaceId: string) {
    //获取相机管理器实例
    this.cameraManager = camera.getCameraManager(this.context!) //需要在Ability中定义globalThis.context=this.context
    //获取所有相机
    this.camerasAll = this.cameraManager.getSupportedCameras()
    //获取前置摄像头
    for (let i = 0; i < this.camerasAll.length; i++) {
      let cameraFront: camera.CameraDevice = this.camerasAll[i];
      if (cameraFront.cameraPosition == 2) {
        this.camera = cameraFront;
        break
      }
    }
    //创建CameraInput实例
    this.cameraInput = this.cameraManager.createCameraInput(this.camera)
    //打开相机
    this.cameraInput.open()
    //创建预览输出对象
    this.mReceiver = image.createImageReceiver(this.screenWidth, this.screenHeight, 4, 8)
    this.mSurfaceId = await this.mReceiver.getReceivingSurfaceId()
    let modes: Array<camera.SceneMode> = this.cameraManager.getSupportedSceneModes(this.camera);
    let cameraOutputCapability: camera.CameraOutputCapability =
      this.cameraManager.getSupportedOutputCapability(this.camera, modes[0]);
    let previewProfiles: Array<camera.Profile> = cameraOutputCapability.previewProfiles;
    this.previewOutput = this.cameraManager.createPreviewOutput(previewProfiles[7],
      surfaceId)
    this.previewOutput.start()
    //创建拍照输出对象
    let photoProfiles: Array<camera.Profile> = cameraOutputCapability.photoProfiles;
    this.photoOutput = this.cameraManager.createPhotoOutput(photoProfiles[photoProfiles.length - 1], this.mSurfaceId)
    //创建CaptureSession实例
    this.photoSession = this.cameraManager.createSession(modes[0]) as camera.PhotoSession
    //开始配置会话
    this.photoSession.beginConfig()
    //将cameraInput加入会话
    this.photoSession.addInput(this.cameraInput)
    //将预览输出加入会话
    this.photoSession.addOutput(this.previewOutput)
    //将照片输出加入会话
    this.photoSession.addOutput(this.photoOutput)
    //提交配置信息
    await this.photoSession.commitConfig()
    //开始输出
    await this.photoSession.start();

    //接收图片时注册回调
    this.mReceiver.on('imageArrival', () => {
      console.error('wkw imageArrival');
      //从ImageReceiver读取下一张图片
      this.mReceiver!.readNextImage((err, image) => {
        let buffer = new ArrayBuffer(4096)
        if (err || image === undefined) {
          return;
        }
        //根据图像的组件类型从图像中获取组件缓存
        image.getComponent(4, (errMsg, img) => {
          if (errMsg || img === undefined) {
            return;
          }
          image.getComponent(4, (errMsg, img) => {
            if (errMsg || img === undefined) {
              return
            }
            if (img.byteBuffer) {
              buffer = img.byteBuffer
            }
            this.savePictureSand(buffer, image)
          })
        });
      });
    });

  }

  //拍摄照片
  async takePicture(): Promise<void> {
    //设置拍照相关参数
    let photoSettings: camera.PhotoCaptureSetting = {
      rotation: camera.ImageRotation.ROTATION_0,
      quality: camera.QualityLevel.QUALITY_LEVEL_MEDIUM,
      mirror: false,
    };
    await this.photoOutput!.capture(photoSettings);
  }

  //保存沙箱路径
  async savePictureSand(buffer: ArrayBuffer, img: image.Image) {
    let context = getContext(this) as common.UIAbilityContext;
    let filesDir = context.cacheDir;
    let timestampStr = Date.now().toString();
    let imgFilePath = filesDir + '/ohos$' + timestampStr + '.jpg';
    this.imgUrl = imgFilePath;
    // 新建并打开文件
    let file = fs.openSync(imgFilePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
    // 写入一段内容至文件
    fs.writeSync(file.fd, buffer);
    // 关闭文件
    fs.closeSync(file);
    img.release();
  }

  build() {
    Column({}) {
      Flex() {
        //相机显示的组件
        XComponent({
          id: 'componentId',
          type: 'surface',
          controller: this.mXComponentController
        }).onLoad(() => {
          this.mXComponentController.setXComponentSurfaceSize({
            surfaceWidth: this.screenWidth,
            surfaceHeight: this.screenHeight
          })
          this.surfaceId = this.mXComponentController.getXComponentSurfaceId()
          this.initCamera(this.surfaceId)
        })
      }.width('100%').height('65%')

      Flex() {
        Button("沙箱路径存储 拍照").onClick(() => {
          this.takePicture()
        }).stateStyles({
          normal: { // 设置默认情况下的显示样式
            .backgroundColor(Color.Blue)
          },
          pressed: { // 设置手指摁下时的显示样式
            .backgroundColor(Color.Pink)
          }
        })
      }

      Flex() {
        Image(decodeURI("file://" + this.imgUrl)).width(100).height(150) //显示沙箱图片
      }

    }
  }

  requestPermissions(permissions: Array<Permissions>, context: common.UIAbilityContext): void {
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    // requestPermissionsFromUser会判断权限的授权状态来决定是否唤起弹窗
    atManager.requestPermissionsFromUser(context, permissions).then((data) => {
      let grantStatus: Array<number> = data.authResults;
      let length: number = grantStatus.length;
      for (let i = 0; i < length; i++) {
        if (grantStatus[i] === 0) {
          // 用户授权,可以继续访问目标操作

        } else {
          // 用户拒绝授权,提示用户必须授权才能访问当前页面的功能,并引导用户到系统设置中打开相应的权限
          return;
        }
      }
      // 授权成功
    }).catch((err: BusinessError) => {
      console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`);
    })
  }
}