I am trying to write a basic iOS app that captures RAW photos with some fixed settings. However I run into a Problem, while taking the photo. The settings that I chose in the configuration of the device (Telecamera of iPhone Xs) are shown in the Preview (fixed Focus, changing lighting, depending on the iso i choose in the code), are not applied when I press the capture button and the capturePhoto method is run. Then I can see the focus adjusting and the torch firing anyway. At first I suspected the session-preset to override my settings, as soon as I start the session, but locking the device until the session is running did not help. Thanks in advance!
My code:
import UIKit
import AVFoundation
import Photos
class ViewController: UIViewController {
//instance variables:
//dispatch-queue for session setup:
var setupQueue = DispatchQueue(label: "sessionSetupQueue")
//session-related:
var captureSession: AVCaptureSession!
var camera: AVCaptureDevice!
var captureInput: AVCaptureInput!
var photoOutput: AVCapturePhotoOutput!
var photoSettings: AVCapturePhotoSettings!
//view-model:
var previewLayer: AVCaptureVideoPreviewLayer!
@IBOutlet weak var capturePreviewView: UIView!
@IBOutlet weak var photoCaptureButton: UIButton!
}
//extension with methods and functions:
extension ViewController {
override func viewDidLoad() {
super.viewDidLoad()
do {
try self.configureSession()
//Create a preview view:
self.previewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession)
self.previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
//connect preview view to UIView object
self.capturePreviewView.layer.insertSublayer(self.previewLayer, at: 0)
self.previewLayer.frame = self.view.frame
} catch {
print("could not set up a CaptureSession!")
return
}
}
//configuration of the capture session
func configureSession() throws {
// create a capture session and set it up for configuration
self.captureSession = AVCaptureSession()
captureSession.sessionPreset = .photo
captureSession.beginConfiguration()
//find tele-camera and set it as input to the session
let camera = AVCaptureDevice.default(.builtInTelephotoCamera, for: .video, position: .back)
self.camera = camera
//configure the device before adding it as an input to the session
do {
try configureDevice()
}
guard let captureInput = try? AVCaptureDeviceInput(device: self.camera!), captureSession.canAddInput(captureInput) else { return }
captureSession.addInput(captureInput)
//Set an output for the session:
self.photoOutput = AVCapturePhotoOutput()
photoOutput.isHighResolutionCaptureEnabled = true
guard captureSession.canAddOutput(photoOutput) else { return }
captureSession.addOutput(photoOutput)
//commit the configuration:
captureSession.commitConfiguration()
//start the session:
captureSession.startRunning()
}
//configure the device
func configureDevice() throws {
//lock the device for setup
do {
try camera.lockForConfiguration()
} catch {
print("could not lock device!")
return
}
//set camera parameters
camera.focusMode = .locked
if camera.isLockingFocusWithCustomLensPositionSupported {
camera.setFocusModeLocked(lensPosition: 1.0, completionHandler: nil)
}
if camera.isExposureModeSupported(.custom) {
camera.setExposureModeCustom(duration: AVCaptureDevice.currentExposureDuration, iso: 60, completionHandler: nil)
}
camera.torchMode = .off
//end setup by unlocking for configuration
camera.unlockForConfiguration()
}
//capture fuction
@IBAction func capturePhoto (_ sender: UIButton) {
//settings configuration
//setup settings for RAW capture
self.photoSettings = AVCapturePhotoSettings(rawPixelFormatType: self.photoOutput.availableRawPhotoPixelFormatTypes.first!)
//disable red eye correction, image stabilization and flash
photoSettings.isAutoRedEyeReductionEnabled = false
photoSettings.isAutoStillImageStabilizationEnabled = false
photoSettings.flashMode = .on
//capture the photo
self.photoOutput.capturePhoto(with: self.photoSettings, delegate: self)
//visual effects:
self.capturePreviewView.layer.opacity = 0
UIView.animate(withDuration: 0.25) {
self.capturePreviewView.layer.opacity = 1
}
}
}
//photoOutput delegate functions:
extension ViewController: AVCapturePhotoCaptureDelegate {
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
if error != nil { print("Error capturing photo!"); return }
PHPhotoLibrary.requestAuthorization { status in
guard status == .authorized else { return }
PHPhotoLibrary.shared().performChanges({
//add captured photos data to asset
let creationRequest = PHAssetCreationRequest.forAsset()
creationRequest.addResource(with: .photo, data: photo.fileDataRepresentation()!, options: nil)
})
}
}
}
I found the solution:
The problem was the flashMode in the photoSettings. Using flashMode = .on overrides most of the device settings i chose beforehand.
In order to evaluate the flash intensity of the scene, the device uses some autofocus and torch.
Without the flash, the custom Exposure was set correctly and the focus stayed fixed.