Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to set fron-facing camera zoom with swift avfoundation

I'm trying to make an app with swift, and I want to use front-facing camera. I used AVFoundation and tried some codes. But I couldn't set front-facing zoom parameter. Is it possible? For back-camera, everything worked successfully.

I dont want to use Affine Transform. Because, it can be decrease image quality. So, how can I set this parameter programatically?

Thanks.

like image 832
gkhanacer Avatar asked Oct 31 '22 05:10

gkhanacer


2 Answers

You'll need to add a zoomFactor variable to your camera.

  var zoomFactor: CGFloat = 1.0

Next define a function zoom to be used in conjunction with a pinch recognizer. I assume you have created a front capture device and input. frontDevice is an optional capture device on my camera. Here's how I zoom that device.

  public func zoom(pinch: UIPinchGestureRecognizer) {
    guard let device = frontDevice 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 pinch.state {
      case .began: fallthrough
      case .changed: update(scale: newScaleFactor)
      case .ended:
        zoomFactor = minMaxZoom(newScaleFactor)
        update(scale: zoomFactor)
      default: break
    }
  }

Finally add a pinch recognizer to some view.

  let pgr = UIPinchGestureRecognizer(target: self, action: #selector(zoom))
  view.addGestureRecognizer(pgr)
like image 150
jnblanchard Avatar answered Nov 15 '22 06:11

jnblanchard


The previous answer can be done without the internal methods, allowing it to be more straightforward and understandable.

To fully explain the code:

The zoom variable keeps track of what zoom you were at after the last gesture. Before any gesture happens there is no zoom, so you're at 1.0.

During a gesture the scale property of pinch holds the ratio of the pinch during the active gesture. This is 1.0 when your fingers haven't moved from their initial position and grows and shrinks with pinching. By multiplying this with the previously held zoom you get what scale to be at in the moment while the gesture is occurring. It's important to keep this scale in the range of [1, device.activeFormat.videoMaxZoomFactor] or you'll get a SIGABRT.

When the gesture finishes (pinch.state) you need to update zoom so that the next gesture starts at the current zoom level.

It's important to lock when modifying a camera property to avoid concurrent modification. defer will release the lock after the block of code no matter what, similar to a finally block.

var zoom: CGFloat = 1.0

@objc func pinch(_ pinch: UIPinchGestureRecognizer) {
    guard let device = frontDevice
      else { return }
    let scaleFactor = min(max(pinch.scale * zoom, 1.0), device.activeFormat.videoMaxZoomFactor)

    if pinch.state == .ended {
      zoom = scaleFactor
    }

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

      device.videoZoomFactor = scaleFactor
    } catch {
      print(error)
    }
}
like image 39
Alex Avatar answered Nov 15 '22 05:11

Alex