AVCaptureDevice Camera Zoom

前端 未结 9 599
没有蜡笔的小新
没有蜡笔的小新 2021-01-31 19:51

I have a simple AVCaptureSession running to get a camera feed in my app and take photos. How can I implement the \'pinch to zoom\' functionality using a UIGestureRecognize

相关标签:
9条回答
  • 2021-01-31 20:20

    I started from the @Gabriel Cartier's solution (thanks). In my code I've preferred to use the smoother rampToVideoZoomFactor and a simpler way to compute the device's scale factor.

    (IBAction) pinchForZoom:(id) sender forEvent:(UIEvent*) event {
        UIPinchGestureRecognizer* pinchRecognizer = (UIPinchGestureRecognizer *)sender;
    
        static CGFloat zoomFactorBegin = .0;
        if ( UIGestureRecognizerStateBegan == pinchRecognizer.state ) {
            zoomFactorBegin = self.captureDevice.videoZoomFactor;
    
        } else if (UIGestureRecognizerStateChanged == pinchRecognizer.state) {
            NSError *error = nil;
            if ([self.captureDevice lockForConfiguration:&error]) {
    
                CGFloat desiredZoomFactor = zoomFactorBegin * pinchRecognizer.scale;
                CGFloat zoomFactor = MAX(1.0, MIN(desiredZoomFactor, self.captureDevice.activeFormat.videoMaxZoomFactor));
                [self.captureDevice rampToVideoZoomFactor:zoomFactor withRate:3.0];
    
                [self.captureDevice unlockForConfiguration];
            } else {
                NSLog(@"error: %@", error);
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-31 20:21

    There is an easier way to handle camera zoom level with pinch recognizer. The only thing you need to do is take cameraDevice.videoZoomFactor and set it to the recognizer on .began state like this

    @objc private func viewPinched(recognizer: UIPinchGestureRecognizer) {
        switch recognizer.state {
            case .began:
                recognizer.scale = cameraDevice.videoZoomFactor
            case .changed:
                let scale = recognizer.scale
                do {
                     try cameraDevice.lockForConfiguration()
                     cameraDevice.videoZoomFactor = max(cameraDevice.minAvailableVideoZoomFactor, min(scale, cameraDevice.maxAvailableVideoZoomFactor))
                     cameraDevice.unlockForConfiguration()
                }
                catch {
                    print(error)
                }
            default:
                break
        }
    }
    
    0 讨论(0)
  • 2021-01-31 20:22

    Swift 4
    Add a pinch gesture recognizer to the front-most view and connect it to this action (pinchToZoom). captureDevice should be the instance currently providing input to the capture session. pinchToZoom provides smooth zooming for both front&back capture devices.

      @IBAction func pinchToZoom(_ pinch: UIPinchGestureRecognizer) {
    
        guard let device = captureDevice else { return }
    
        func minMaxZoom(_ factor: CGFloat) -> CGFloat { return min(max(factor, 1.0), device.activeFormat.videoMaxZoomFactor) }
    
        func update(scale factor: CGFloat) {
          do {
            try device.lockForConfiguration()
            defer { device.unlockForConfiguration() }
            device.videoZoomFactor = factor
          } catch {
            debugPrint(error)
          } 
        }
    
        let newScaleFactor = minMaxZoom(pinch.scale * zoomFactor)
    
        switch sender.state {
          case .began: fallthrough
          case .changed: update(scale: newScaleFactor)
          case .ended:
            zoomFactor = minMaxZoom(newScaleFactor)
            update(scale: zoomFactor)
         default: break
       }
     }
    

    It'll be useful to declare zoomFactor on your camera or vc. I usually put it on the same singleton that has AVCaptureSession. This will act as a default value for captureDevice's videoZoomFactor.

    var zoomFactor: Float = 1.0
    
    0 讨论(0)
提交回复
热议问题