AVFoundation自定义拍照

项目中需要打开相机不停拍照,直到用户点击返回才结束,第三方框架都不满足需求,就只能自己动手做了。简单记录下关键部分,至于界面的自定义就不做介绍了。

1、初始化摄像头

func initCamera() {
    if #available(iOS 10.0, *) {
      self.captureDevice = AVCaptureDevice.default(AVCaptureDevice.DeviceType.builtInWideAngleCamera, for: AVMediaType.video, position: self.positon)
    } else {
      self.captureDevice = AVCaptureDevice.default(for: AVMediaType.video)
    }
    try! self.captureDevice.lockForConfiguration()
    if self.captureDevice.isFocusModeSupported(.autoFocus) {
      self.captureDevice.focusMode = .autoFocus
    }
    self.captureDevice.unlockForConfiguration()
    let input:AVCaptureDeviceInput
    do {
      input =  try AVCaptureDeviceInput(device: self.captureDevice)
    }catch{
      self.showWithError(message: "处理输入源失败")
      return
    }
    self.captureDeviceInput = input
    if captureSession.canAddInput(self.captureDeviceInput) {
      self.captureSession.addInput(self.captureDeviceInput)
    }
    
    if #available(iOS 10.0, *) {
      let output:AVCapturePhotoOutput = AVCapturePhotoOutput()
      output.isHighResolutionCaptureEnabled = true
      self.photoOutput = output
    } else {
      // Fallback on earlier versions
      let output:AVCaptureStillImageOutput = AVCaptureStillImageOutput()
      output.outputSettings = [AVVideoCodecKey:AVVideoCodecJPEG]
      self.photoOutput = output
    }
    if captureSession.canAddOutput(photoOutput){
      self.captureSession.addOutput(photoOutput)
    }
    let layer = AVCaptureVideoPreviewLayer(session: captureSession)
    layer.videoGravity = AVLayerVideoGravity.resizeAspectFill
    layer.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
    layer.frame = self.cameraView.layer.bounds
    self.cameraView.layer.insertSublayer(layer, at: 1)
  }
2、点击拍照按钮进行拍照
@objc func startTakePhoto() {
    if #available(iOS 10.0, *) {
      let photoSettings = AVCapturePhotoSettings()
      photoSettings.isAutoStillImageStabilizationEnabled = true
      photoSettings.isHighResolutionPhotoEnabled = true
      photoSettings.flashMode = self.flashMode
      let output:AVCapturePhotoOutput = (self.photoOutput as! AVCapturePhotoOutput)
      output.capturePhoto(with: photoSettings, delegate: self)
    } else {
      let output:AVCaptureStillImageOutput = (self.photoOutput as! AVCaptureStillImageOutput)
      let videoConnection:AVCaptureConnection? = output.connection(with: AVMediaType.video)
      if videoConnection == nil {
        return
      }
      output.captureStillImageAsynchronously(from: videoConnection!) { (imageDataSampleBuffer, error) in
        if imageDataSampleBuffer == nil {
          return
        }
        let imageData:Data = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer!)!
        self.takePhotoResult(imageData: imageData)
      }
    }
  }
此处需要注意,ios10及以上系统需要实现代理来获取拍照内容

AVCapturePhotoCaptureDelegate代理实现如下

@available(iOS 10.0, *)
extension TakePhotoVC:AVCapturePhotoCaptureDelegate {
  func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photoSampleBuffer: CMSampleBuffer?, previewPhoto previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?) {
    if photoSampleBuffer == nil {
      return
    }
    let imageData:Data? = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: photoSampleBuffer!, previewPhotoSampleBuffer: previewPhotoSampleBuffer)
    self.takePhotoResult(imageData: imageData)
  }
}

3、获取拍照结果

func takePhotoResult(imageData:Data?) {
    if imageData == nil {
      return
    }
    let image = UIImage(data: imageData!)
    if image == nil {
      return
    }
    self.imageArray.append(image!)
    self.reloadImageView()
    //压缩图片
    let imageTemp = image!.wxCompress()
    //给图片打水印
    let waterImage = BsUtils.textWaterImage(image: imageTemp, text: DateUtil.getDateFormatter(date: Date(), format: "yyyy-MM-dd HH:mm"))
    if waterImage == nil {
      return
    }
    let imagePath = FileHelper.saveImage(tempImage: waterImage!, imageName: "\(UUID().uuidString).jpg", dirName: AppConfig.upload_file_dir, isCompression: false)
    self.didFinishCapturePhotoOnce?(imageTemp,imagePath ?? "")
  }

4、打开或关闭手电筒

@objc func torchBtnClick(button:UIButton) {
    if button.tag == 1 {
      //开启电筒
      if !self.captureDevice.isTorchModeSupported(.on){
        return
      }
      self.torchMode = .on
    }else{
      if !self.captureDevice.isTorchModeSupported(.off){
        return
      }
      //关闭电筒
      self.torchMode = .off
      button.tag = 1
    }
    self.updateDeviceTorchMode()
  }
func updateDeviceTorchMode() {
    try! self.captureDevice.lockForConfiguration()
    if self.captureDevice.isTorchModeSupported(self.torchMode) {
        self.captureDevice?.torchMode = self.torchMode
    }
    self.captureDevice.unlockForConfiguration()
  }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值