@@ -36,6 +36,87 @@ public enum CameraOutputQuality: Int {
3636 case low, medium, high
3737}
3838
39+ public enum CaptureResult {
40+ case success( content: CaptureContent )
41+ case failure( Error )
42+
43+ init ( _ image: UIImage ) {
44+ self = . success( content: . image( image) )
45+ }
46+
47+ init ( _ data: Data ) {
48+ self = . success( content: . imageData( data) )
49+ }
50+
51+ init ( _ asset: PHAsset ) {
52+ self = . success( content: . asset( asset) )
53+ }
54+
55+ var imageData : Data ? {
56+ if case let . success( content) = self {
57+ return content. asData
58+ } else {
59+
60+ return nil
61+ }
62+ }
63+ }
64+
65+ public enum CaptureContent {
66+ case imageData( Data )
67+ case image( UIImage )
68+ case asset( PHAsset )
69+ }
70+
71+ extension CaptureContent {
72+
73+ public var asImage : UIImage ? {
74+
75+ switch self {
76+ case let . image( image) : return image
77+ case let . imageData( data) : return UIImage ( data: data)
78+ case let . asset( asset) :
79+ if let data = getImageData ( fromAsset: asset) {
80+ return UIImage ( data: data)
81+ } else {
82+ return nil
83+ }
84+ }
85+ }
86+
87+ public var asData : Data ? {
88+
89+ switch self {
90+ case let . image( image) : return image. jpegData ( compressionQuality: 0.8 )
91+ case let . imageData( data) : return data
92+ case let . asset( asset) : return getImageData ( fromAsset: asset)
93+ }
94+
95+ }
96+
97+ private func getImageData( fromAsset asset: PHAsset ) -> Data ? {
98+
99+ var imageData : Data ? = nil
100+ let manager = PHImageManager . default ( )
101+ let options = PHImageRequestOptions ( )
102+ options. version = . original
103+ options. isSynchronous = true
104+ manager. requestImageData ( for: asset, options: options) { data, _, _, _ in
105+
106+ imageData = data
107+ }
108+ return imageData
109+ }
110+ }
111+
112+ public enum CaptureError : Error {
113+
114+ case noImageData
115+ case invalidImageData
116+ case noVideoConnection
117+ case noSampleBuffer
118+ case assetNotSaved
119+ }
39120
40121/// Class for handling iDevices custom camera usage
41122open class CameraManager : NSObject , AVCaptureFileOutputRecordingDelegate , UIGestureRecognizerDelegate {
@@ -407,16 +488,45 @@ open class CameraManager: NSObject, AVCaptureFileOutputRecordingDelegate, UIGest
407488 self . movieOutput = nil
408489 self . animateCameraDeviceChange = oldAnimationValue
409490 }
410-
491+
411492 /**
412493 Captures still image from currently running capture session.
413-
494+
414495 :param: imageCompletion Completion block containing the captured UIImage
415496 */
497+ @available ( * , deprecated)
416498 open func capturePictureWithCompletion( _ imageCompletion: @escaping ( UIImage ? , NSError ? ) -> Void ) {
417- self . capturePictureDataWithCompletion { data, error in
418- guard error == nil , let imageData = data else {
419- imageCompletion ( nil , error)
499+
500+ func completion( _ result: CaptureResult ) {
501+
502+ switch result {
503+
504+ case let . success( content) :
505+ imageCompletion ( content. asImage, nil )
506+ case . failure:
507+ imageCompletion ( nil , NSError ( ) )
508+ }
509+ }
510+
511+ capturePictureWithCompletion ( completion)
512+ }
513+
514+ /**
515+ Captures still image from currently running capture session.
516+
517+ :param: imageCompletion Completion block containing the captured UIImage
518+ */
519+ open func capturePictureWithCompletion( _ imageCompletion: @escaping ( CaptureResult ) -> Void ) {
520+ self . capturePictureDataWithCompletion { result in
521+
522+ guard let imageData = result. imageData else {
523+
524+ if case let . failure( error) = result {
525+ imageCompletion ( . failure( error) )
526+ } else {
527+ imageCompletion ( . failure( CaptureError . noImageData) )
528+ }
529+
420530 return
421531 }
422532
@@ -430,9 +540,9 @@ open class CameraManager: NSObject, AVCaptureFileOutputRecordingDelegate, UIGest
430540 }
431541 }
432542
433- fileprivate func _capturePicture( _ imageData: Data , _ imageCompletion: @escaping ( UIImage ? , NSError ? ) -> Void ) {
543+ fileprivate func _capturePicture( _ imageData: Data , _ imageCompletion: @escaping ( CaptureResult ) -> Void ) {
434544 guard let img = UIImage ( data: imageData) else {
435- imageCompletion ( nil , NSError ( ) )
545+ imageCompletion ( . failure ( NSError ( ) ) )
436546 return
437547 }
438548
@@ -459,12 +569,12 @@ open class CameraManager: NSObject, AVCaptureFileOutputRecordingDelegate, UIGest
459569 }
460570
461571 } catch {
462- imageCompletion ( nil , NSError ( ) )
572+ imageCompletion ( . failure ( error ) )
463573 return
464574 }
465575 }
466576
467- imageCompletion ( image, nil )
577+ imageCompletion ( CaptureResult ( image) )
468578 }
469579
470580 fileprivate func _setVideoWithGPS( forLocation location: CLLocation ) {
@@ -525,20 +635,48 @@ open class CameraManager: NSObject, AVCaptureFileOutputRecordingDelegate, UIGest
525635 return GPSMetadata
526636 }
527637
528- fileprivate func _saveImageToLibrary( atFileURL filePath: URL , _ imageCompletion: @escaping ( UIImage ? , NSError ? ) -> Void ) {
638+ fileprivate func _saveImageToLibrary( atFileURL filePath: URL , _ imageCompletion: @escaping ( CaptureResult ) -> Void ) {
529639
530640 let location = self . locationManager? . latestLocation
531641 let date = Date ( )
532642
533- library!. save ( imageAtURL: filePath, albumName: self . imageAlbumName, date: date, location: location)
643+ library? . save ( imageAtURL: filePath, albumName: self . imageAlbumName, date: date, location: location) { asset in
644+
645+ if let asset = asset {
646+ imageCompletion ( CaptureResult ( asset) )
647+ } else {
648+ imageCompletion ( . failure( CaptureError . assetNotSaved) )
649+ }
650+ }
534651 }
535652
536653 /**
537654 Captures still image from currently running capture session.
538655
539656 :param: imageCompletion Completion block containing the captured imageData
540657 */
658+ @available ( * , deprecated)
541659 open func capturePictureDataWithCompletion( _ imageCompletion: @escaping ( Data ? , NSError ? ) -> Void ) {
660+
661+ func completion( _ result: CaptureResult ) {
662+
663+ switch result {
664+
665+ case let . success( content) :
666+ imageCompletion ( content. asData, nil )
667+ case . failure:
668+ imageCompletion ( nil , NSError ( ) )
669+ }
670+ }
671+ capturePictureDataWithCompletion ( completion)
672+ }
673+
674+ /**
675+ Captures still image from currently running capture session.
676+
677+ :param: imageCompletion Completion block containing the captured imageData
678+ */
679+ open func capturePictureDataWithCompletion( _ imageCompletion: @escaping ( CaptureResult ) -> Void ) {
542680 guard cameraIsSetup else {
543681 _show ( NSLocalizedString ( " No capture session setup " , comment: " " ) , message: NSLocalizedString ( " I can't take any picture " , comment: " " ) )
544682 return
@@ -569,17 +707,20 @@ open class CameraManager: NSObject, AVCaptureFileOutputRecordingDelegate, UIGest
569707 DispatchQueue . main. async ( execute: {
570708 self ? . _show ( NSLocalizedString ( " Error " , comment: " " ) , message: error. localizedDescription)
571709 } )
572- imageCompletion ( nil , error as NSError ? )
710+ imageCompletion ( . failure ( error) )
573711 return
574712 }
575713
576- guard let sample = sample else { imageCompletion ( nil , NSError ( ) ) ; return }
577- let imageData = AVCaptureStillImageOutput . jpegStillImageNSDataRepresentation ( sample)
578- imageCompletion ( imageData, nil )
714+ guard let sample = sample else { imageCompletion ( . failure( CaptureError . noSampleBuffer) ) ; return }
715+ if let imageData = AVCaptureStillImageOutput . jpegStillImageNSDataRepresentation ( sample) {
716+ imageCompletion ( CaptureResult ( imageData) )
717+ } else {
718+ imageCompletion ( . failure( CaptureError . noImageData) )
719+ }
579720
580721 } )
581722 } else {
582- imageCompletion ( nil , NSError ( ) )
723+ imageCompletion ( . failure ( CaptureError . noVideoConnection ) )
583724 }
584725 } )
585726 }
0 commit comments