2021-02-19 08:28:05 -07:00
|
|
|
//
|
2023-09-01 04:58:32 -06:00
|
|
|
// CameraView+Focus.swift
|
2021-06-21 14:42:46 -06:00
|
|
|
// mrousavy
|
2021-02-19 08:28:05 -07:00
|
|
|
//
|
|
|
|
// Created by Marc Rousavy on 19.02.21.
|
2021-06-01 05:07:57 -06:00
|
|
|
// Copyright © 2021 mrousavy. All rights reserved.
|
2021-02-19 08:28:05 -07:00
|
|
|
//
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
|
|
|
|
extension CameraView {
|
2023-10-06 06:30:12 -06:00
|
|
|
private func convertPreviewCoordinatesToCameraCoordinates(_ point: CGPoint) -> CGPoint {
|
|
|
|
return previewView.captureDevicePointConverted(fromLayerPoint: point)
|
2023-02-21 07:00:48 -07:00
|
|
|
}
|
|
|
|
|
2021-02-19 08:28:05 -07:00
|
|
|
func focus(point: CGPoint, promise: Promise) {
|
|
|
|
withPromise(promise) {
|
|
|
|
guard let device = self.videoDeviceInput?.device else {
|
|
|
|
throw CameraError.session(SessionError.cameraNotReady)
|
|
|
|
}
|
|
|
|
if !device.isFocusPointOfInterestSupported {
|
|
|
|
throw CameraError.device(DeviceError.focusNotSupported)
|
|
|
|
}
|
2021-02-25 05:59:50 -07:00
|
|
|
|
2023-02-21 07:00:48 -07:00
|
|
|
// in {0..1} system
|
2023-10-06 06:30:12 -06:00
|
|
|
let normalizedPoint = convertPreviewCoordinatesToCameraCoordinates(point)
|
2021-02-25 05:59:50 -07:00
|
|
|
|
2021-02-19 08:28:05 -07:00
|
|
|
do {
|
|
|
|
try device.lockForConfiguration()
|
2023-10-06 06:30:12 -06:00
|
|
|
defer {
|
|
|
|
device.unlockForConfiguration()
|
|
|
|
}
|
2021-02-25 05:59:50 -07:00
|
|
|
|
2023-10-06 06:30:12 -06:00
|
|
|
// Set Focus
|
|
|
|
if device.isFocusPointOfInterestSupported {
|
|
|
|
device.focusPointOfInterest = normalizedPoint
|
|
|
|
device.focusMode = .autoFocus
|
|
|
|
}
|
2021-02-25 05:59:50 -07:00
|
|
|
|
2023-10-06 06:30:12 -06:00
|
|
|
// Set Exposure
|
2021-02-19 08:28:05 -07:00
|
|
|
if device.isExposurePointOfInterestSupported {
|
|
|
|
device.exposurePointOfInterest = normalizedPoint
|
2023-10-06 06:30:12 -06:00
|
|
|
device.exposureMode = .autoExpose
|
2021-02-19 08:28:05 -07:00
|
|
|
}
|
2021-02-25 05:59:50 -07:00
|
|
|
|
2023-10-06 06:30:12 -06:00
|
|
|
// Remove any existing listeners
|
|
|
|
NotificationCenter.default.removeObserver(self,
|
|
|
|
name: NSNotification.Name.AVCaptureDeviceSubjectAreaDidChange,
|
|
|
|
object: nil)
|
|
|
|
|
|
|
|
// Listen for focus completion
|
|
|
|
device.isSubjectAreaChangeMonitoringEnabled = true
|
|
|
|
NotificationCenter.default.addObserver(self,
|
|
|
|
selector: #selector(subjectAreaDidChange),
|
|
|
|
name: NSNotification.Name.AVCaptureDeviceSubjectAreaDidChange,
|
|
|
|
object: nil)
|
2021-02-19 08:28:05 -07:00
|
|
|
return nil
|
|
|
|
} catch {
|
|
|
|
throw CameraError.device(DeviceError.configureError)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-10-06 06:30:12 -06:00
|
|
|
|
|
|
|
@objc
|
|
|
|
func subjectAreaDidChange(notification _: NSNotification) {
|
|
|
|
guard let device = videoDeviceInput?.device else {
|
|
|
|
invokeOnError(.session(.cameraNotReady))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
try device.lockForConfiguration()
|
|
|
|
defer {
|
|
|
|
device.unlockForConfiguration()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset Focus to continuous/auto
|
|
|
|
if device.isFocusPointOfInterestSupported {
|
|
|
|
device.focusMode = .continuousAutoFocus
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset Exposure to continuous/auto
|
|
|
|
if device.isExposurePointOfInterestSupported {
|
|
|
|
device.exposureMode = .continuousAutoExposure
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disable listeners
|
|
|
|
device.isSubjectAreaChangeMonitoringEnabled = false
|
|
|
|
} catch {
|
|
|
|
invokeOnError(.device(.configureError))
|
|
|
|
}
|
|
|
|
}
|
2021-02-19 08:28:05 -07:00
|
|
|
}
|