react-native-vision-camera/package/ios/CameraView+TakePhoto.swift
Marc Rousavy 6e72781500
feat: Use correct photo and video format dimensions on iOS (#1929)
* feat: Use new photo dimensions API

* Update AVCaptureDevice.Format+matchesFilter.swift

* fix: Use Pixels instead of Points for video size

* feat: Set `PhotoOutput`'s maximum photo resolution

* fix: Compare dictionaries instead

* chore: Format code

* fix: Try to use hash.... failing atm

* fix: Use rough comparison again

* fix: Also take video HDR into consideration

* chore: Format

* Use contains

* Update AVCaptureDevice.Format+toDictionary.swift

* docs: Add better docs to Camera props

* Update CameraView+AVCaptureSession.swift

* Update CameraView+AVCaptureSession.swift
2023-10-06 16:11:09 +02:00

93 lines
3.6 KiB
Swift

//
// CameraView+TakePhoto.swift
// mrousavy
//
// Created by Marc Rousavy on 16.12.20.
// Copyright © 2020 mrousavy. All rights reserved.
//
import AVFoundation
extension CameraView {
func takePhoto(options: NSDictionary, promise: Promise) {
CameraQueues.cameraQueue.async {
guard let photoOutput = self.photoOutput,
let videoDeviceInput = self.videoDeviceInput else {
if self.photo?.boolValue == true {
promise.reject(error: .session(.cameraNotReady))
return
} else {
promise.reject(error: .capture(.photoNotEnabled))
return
}
}
ReactLogger.log(level: .info, message: "Capturing photo...")
// Create photo settings
let photoSettings = AVCapturePhotoSettings()
// default, overridable settings if high quality capture was enabled
if self.enableHighQualityPhotos?.boolValue == true {
// TODO: On iOS 16+ this will be removed in favor of maxPhotoDimensions.
photoSettings.isHighResolutionPhotoEnabled = true
if #available(iOS 13.0, *) {
photoSettings.photoQualityPrioritization = .quality
}
}
// flash
if videoDeviceInput.device.isFlashAvailable, let flash = options["flash"] as? String {
guard let flashMode = AVCaptureDevice.FlashMode(withString: flash) else {
promise.reject(error: .parameter(.invalid(unionName: "FlashMode", receivedValue: flash)))
return
}
photoSettings.flashMode = flashMode
}
// shutter sound
let enableShutterSound = options["enableShutterSound"] as? Bool ?? true
// depth data
photoSettings.isDepthDataDeliveryEnabled = photoOutput.isDepthDataDeliveryEnabled
if #available(iOS 12.0, *) {
photoSettings.isPortraitEffectsMatteDeliveryEnabled = photoOutput.isPortraitEffectsMatteDeliveryEnabled
}
// quality prioritization
if #available(iOS 13.0, *), let qualityPrioritization = options["qualityPrioritization"] as? String {
guard let photoQualityPrioritization = AVCapturePhotoOutput.QualityPrioritization(withString: qualityPrioritization) else {
promise.reject(error: .parameter(.invalid(unionName: "QualityPrioritization", receivedValue: qualityPrioritization)))
return
}
photoSettings.photoQualityPrioritization = photoQualityPrioritization
}
// photo size is always the one selected in the format
if #available(iOS 16.0, *) {
photoSettings.maxPhotoDimensions = photoOutput.maxPhotoDimensions
}
// red-eye reduction
if #available(iOS 12.0, *), let autoRedEyeReduction = options["enableAutoRedEyeReduction"] as? Bool {
photoSettings.isAutoRedEyeReductionEnabled = autoRedEyeReduction
}
// stabilization
if let enableAutoStabilization = options["enableAutoStabilization"] as? Bool {
photoSettings.isAutoStillImageStabilizationEnabled = enableAutoStabilization
}
// distortion correction
if #available(iOS 14.1, *), let enableAutoDistortionCorrection = options["enableAutoDistortionCorrection"] as? Bool {
photoSettings.isAutoContentAwareDistortionCorrectionEnabled = enableAutoDistortionCorrection
}
photoOutput.capturePhoto(with: photoSettings, delegate: PhotoCaptureDelegate(promise: promise, enableShutterSound: enableShutterSound))
// Assume that `takePhoto` is always called with the same parameters, so prepare the next call too.
photoOutput.setPreparedPhotoSettingsArray([photoSettings], completionHandler: nil)
}
}
}