3

I want to implement a simple pinch to zoom gesture in a QR app.
It seems simple, so I did some researches I found a few possible answers to the problem:

AVCaptureDevice Camera Zoom
How to implement "pinch to zoom" in custom camera
Pinch to zoom camera
Zooming while capturing video using AVCapture in iOS

Unfortunately none of those actually solve it as I wanted, I personally liked the first one (in Objective-C) and I tried to do it in Swift 3.

I posted an answer with the code that I came up with after some tries, other easier/better/simpler solutions are welcomed :)

Community
  • 1
  • 1
Daniel Illescas
  • 5,346
  • 3
  • 17
  • 23
  • 2
    It's fine to post your own question and answer but both the question and the answer must adhere to the normal rules for good questions and answers. This question is not an acceptable question by the rules of this site. Please update it to make it a proper question. – rmaddy Apr 07 '17 at 14:03

2 Answers2

15

I used the Pinch Gesture Recognizer from the storyboard, then linked this action:

@IBAction func pinchToZoom(_ sender: UIPinchGestureRecognizer) {

        guard let device = captureDevice else { return }

        if sender.state == .changed {

            let maxZoomFactor = device.activeFormat.videoMaxZoomFactor
            let pinchVelocityDividerFactor: CGFloat = 5.0

            do {

                try device.lockForConfiguration()
                defer { device.unlockForConfiguration() }

                let desiredZoomFactor = device.videoZoomFactor + atan2(sender.velocity, pinchVelocityDividerFactor)
                device.videoZoomFactor = max(1.0, min(desiredZoomFactor, maxZoomFactor))

            } catch {
                print(error)
            }
        }
    }

Note that captureDevice is an optional object of the class AVCaptureDevice.

Daniel Illescas
  • 5,346
  • 3
  • 17
  • 23
0
@IBAction func pinchToZoom(_ sender: 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(sender.scale * zoomFactor)

  switch sender.state {
    case .began: fallthrough
    case .changed: update(scale: newScaleFactor)
    case .ended:
      zoomFactor = minMaxZoom(newScaleFactor)
      update(scale: zoomFactor)
    default: break
  }
}
jnblanchard
  • 1,182
  • 12
  • 12
  • This code won't compile. At least 'pinch.scale' and zoomFactor is not declared. This one should work https://stackoverflow.com/a/42928452/5969121 – atereshkov Aug 25 '19 at 17:57