Skip to content

Instantly share code, notes, and snippets.

@rorodriguez116
Created October 23, 2020 20:58
Show Gist options
  • Save rorodriguez116/018a13c1b496589531775b1cca0c309d to your computer and use it in GitHub Desktop.
Save rorodriguez116/018a13c1b496589531775b1cca0c309d to your computer and use it in GitHub Desktop.
PhotoCaptureProcessor implemented AVCapturePhotoCaptureDelegate
import Photos
class PhotoCaptureProcessor: NSObject {
lazy var context = CIContext()
private(set) var requestedPhotoSettings: AVCapturePhotoSettings
private let willCapturePhotoAnimation: () -> Void
private let completionHandler: (PhotoCaptureProcessor) -> Void
private let photoProcessingHandler: (Bool) -> Void
// The actual captured photo's data
var photoData: Data?
// The maximum time lapse before telling UI to show a spinner
private var maxPhotoProcessingTime: CMTime?
// Init takes multiple closures to be called in each step of the photco capture process
init(with requestedPhotoSettings: AVCapturePhotoSettings, willCapturePhotoAnimation: @escaping () -> Void, completionHandler: @escaping (PhotoCaptureProcessor) -> Void, photoProcessingHandler: @escaping (Bool) -> Void) {
self.requestedPhotoSettings = requestedPhotoSettings
self.willCapturePhotoAnimation = willCapturePhotoAnimation
self.completionHandler = completionHandler
self.photoProcessingHandler = photoProcessingHandler
}
}
extension PhotoCaptureProcessor: AVCapturePhotoCaptureDelegate {
// This extension adopts AVCapturePhotoCaptureDelegate protocol methods.
/// - Tag: WillBeginCapture
func photoOutput(_ output: AVCapturePhotoOutput, willBeginCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings) {
maxPhotoProcessingTime = resolvedSettings.photoProcessingTimeRange.start + resolvedSettings.photoProcessingTimeRange.duration
}
/// - Tag: WillCapturePhoto
func photoOutput(_ output: AVCapturePhotoOutput, willCapturePhotoFor resolvedSettings: AVCaptureResolvedPhotoSettings) {
DispatchQueue.main.async {
self.willCapturePhotoAnimation()
}
guard let maxPhotoProcessingTime = maxPhotoProcessingTime else {
return
}
// Show a spinner if processing time exceeds one second.
let oneSecond = CMTime(seconds: 2, preferredTimescale: 1)
if maxPhotoProcessingTime > oneSecond {
DispatchQueue.main.async {
self.photoProcessingHandler(true)
}
}
}
/// - Tag: DidFinishProcessingPhoto
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
DispatchQueue.main.async {
self.photoProcessingHandler(false)
}
if let error = error {
print("Error capturing photo: \(error)")
} else {
photoData = photo.fileDataRepresentation()
}
}
// MARK: Saves capture to photo library
func saveToPhotoLibrary(_ photoData: Data) {
PHPhotoLibrary.requestAuthorization { status in
if status == .authorized {
PHPhotoLibrary.shared().performChanges({
let options = PHAssetResourceCreationOptions()
let creationRequest = PHAssetCreationRequest.forAsset()
options.uniformTypeIdentifier = self.requestedPhotoSettings.processedFileType.map { $0.rawValue }
creationRequest.addResource(with: .photo, data: photoData, options: options)
}, completionHandler: { _, error in
if let error = error {
print("Error occurred while saving photo to photo library: \(error)")
}
DispatchQueue.main.async {
self.completionHandler(self)
}
}
)
} else {
DispatchQueue.main.async {
self.completionHandler(self)
}
}
}
}
/// - Tag: DidFinishCapture
func photoOutput(_ output: AVCapturePhotoOutput, didFinishCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings, error: Error?) {
if let error = error {
print("Error capturing photo: \(error)")
DispatchQueue.main.async {
self.completionHandler(self)
}
return
} else {
guard let data = photoData else {
DispatchQueue.main.async {
self.completionHandler(self)
}
return
}
self.saveToPhotoLibrary(data)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment