| 
									
										
										
										
											2021-02-19 16:28:05 +01:00
										 |  |  | // | 
					
						
							|  |  |  | //  PhotoCaptureDelegate.swift | 
					
						
							| 
									
										
										
										
											2021-06-21 22:42:46 +02:00
										 |  |  | //  mrousavy | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:05 +01:00
										 |  |  | // | 
					
						
							|  |  |  | //  Created by Marc Rousavy on 15.12.20. | 
					
						
							| 
									
										
										
										
											2021-06-01 13:07:57 +02:00
										 |  |  | //  Copyright © 2020 mrousavy. All rights reserved. | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:05 +01:00
										 |  |  | // | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import AVFoundation | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private var delegatesReferences: [NSObject] = [] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-09 10:53:29 +01:00
										 |  |  | // MARK: - PhotoCaptureDelegate | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:05 +01:00
										 |  |  | class PhotoCaptureDelegate: NSObject, AVCapturePhotoCaptureDelegate { | 
					
						
							| 
									
										
										
										
											2021-06-09 11:14:49 +02:00
										 |  |  |   private let promise: Promise | 
					
						
							| 
									
										
										
										
											2023-08-21 15:27:42 +02:00
										 |  |  |   private let enableShutterSound: Bool | 
					
						
							| 
									
										
										
										
											2021-06-09 11:14:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-21 15:27:42 +02:00
										 |  |  |   required init(promise: Promise, enableShutterSound: Bool) { | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:05 +01:00
										 |  |  |     self.promise = promise | 
					
						
							| 
									
										
										
										
											2023-08-21 15:27:42 +02:00
										 |  |  |     self.enableShutterSound = enableShutterSound | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:05 +01:00
										 |  |  |     super.init() | 
					
						
							|  |  |  |     delegatesReferences.append(self) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-21 15:27:42 +02:00
										 |  |  |   func photoOutput(_: AVCapturePhotoOutput, willCapturePhotoFor _: AVCaptureResolvedPhotoSettings) { | 
					
						
							|  |  |  |     if !enableShutterSound { | 
					
						
							|  |  |  |       // disable system shutter sound (see https://stackoverflow.com/a/55235949/5281431) | 
					
						
							|  |  |  |       AudioServicesDisposeSystemSoundID(1108) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:05 +01:00
										 |  |  |   func photoOutput(_: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) { | 
					
						
							|  |  |  |     defer { | 
					
						
							|  |  |  |       delegatesReferences.removeAll(where: { $0 == self }) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-03-26 16:20:57 +01:00
										 |  |  |     if let error = error as NSError? { | 
					
						
							| 
									
										
										
										
											2021-06-09 11:14:49 +02:00
										 |  |  |       promise.reject(error: .capture(.unknown(message: error.description)), cause: error) | 
					
						
							|  |  |  |       return | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:05 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     let error = ErrorPointer(nilLiteral: ()) | 
					
						
							|  |  |  |     guard let tempFilePath = RCTTempFilePath("jpeg", error) | 
					
						
							|  |  |  |     else { | 
					
						
							| 
									
										
										
										
											2021-06-09 11:14:49 +02:00
										 |  |  |       promise.reject(error: .capture(.createTempFileError), cause: error?.pointee) | 
					
						
							|  |  |  |       return | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:05 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     let url = URL(string: "file://\(tempFilePath)")! | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-09 11:14:49 +02:00
										 |  |  |     guard let data = photo.fileDataRepresentation() else { | 
					
						
							|  |  |  |       promise.reject(error: .capture(.fileError)) | 
					
						
							|  |  |  |       return | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:05 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     do { | 
					
						
							|  |  |  |       try data.write(to: url) | 
					
						
							|  |  |  |       let exif = photo.metadata["{Exif}"] as? [String: Any] | 
					
						
							|  |  |  |       let width = exif?["PixelXDimension"] | 
					
						
							|  |  |  |       let height = exif?["PixelYDimension"] | 
					
						
							| 
									
										
										
										
											2023-08-21 12:50:14 +02:00
										 |  |  |       let exifOrientation = photo.metadata[kCGImagePropertyOrientation as String] as? Int ?? 0 | 
					
						
							|  |  |  |       let orientation = getOrientation(forExifOrientation: exifOrientation) | 
					
						
							|  |  |  |       let isMirrored = getIsMirrored(forExifOrientation: exifOrientation) | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-09 11:14:49 +02:00
										 |  |  |       promise.resolve([ | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:05 +01:00
										 |  |  |         "path": tempFilePath, | 
					
						
							|  |  |  |         "width": width as Any, | 
					
						
							|  |  |  |         "height": height as Any, | 
					
						
							| 
									
										
										
										
											2023-08-21 12:50:14 +02:00
										 |  |  |         "orientation": orientation, | 
					
						
							|  |  |  |         "isMirrored": isMirrored, | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:05 +01:00
										 |  |  |         "isRawPhoto": photo.isRawPhoto, | 
					
						
							|  |  |  |         "metadata": photo.metadata, | 
					
						
							|  |  |  |         "thumbnail": photo.embeddedThumbnailPhotoFormat as Any, | 
					
						
							|  |  |  |       ]) | 
					
						
							|  |  |  |     } catch { | 
					
						
							| 
									
										
										
										
											2021-06-09 11:14:49 +02:00
										 |  |  |       promise.reject(error: .capture(.fileError), cause: error as NSError) | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:05 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   func photoOutput(_: AVCapturePhotoOutput, didFinishCaptureFor _: AVCaptureResolvedPhotoSettings, error: Error?) { | 
					
						
							|  |  |  |     defer { | 
					
						
							|  |  |  |       delegatesReferences.removeAll(where: { $0 == self }) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-03-26 16:20:57 +01:00
										 |  |  |     if let error = error as NSError? { | 
					
						
							| 
									
										
										
										
											2021-06-09 11:14:49 +02:00
										 |  |  |       promise.reject(error: .capture(.unknown(message: error.description)), cause: error) | 
					
						
							|  |  |  |       return | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:05 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-08-21 12:50:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   private func getOrientation(forExifOrientation exifOrientation: Int) -> String { | 
					
						
							|  |  |  |     switch exifOrientation { | 
					
						
							|  |  |  |     case 1, 2: | 
					
						
							|  |  |  |       return "portrait" | 
					
						
							|  |  |  |     case 3, 4: | 
					
						
							|  |  |  |       return "portrait-upside-down" | 
					
						
							|  |  |  |     case 5, 6: | 
					
						
							|  |  |  |       return "landscape-left" | 
					
						
							|  |  |  |     case 7, 8: | 
					
						
							|  |  |  |       return "landscape-right" | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return "portrait" | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private func getIsMirrored(forExifOrientation exifOrientation: Int) -> Bool { | 
					
						
							|  |  |  |     switch exifOrientation { | 
					
						
							|  |  |  |     case 2, 4, 5, 7: | 
					
						
							|  |  |  |       return true | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       return false | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:05 +01:00
										 |  |  | } |