DKCamera.swift 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. //
  2. // DKCamera.swift
  3. // DKCameraDemo
  4. //
  5. // Created by ZhangAo on 15/8/30.
  6. // Copyright (c) 2015年 ZhangAo. All rights reserved.
  7. //
  8. import UIKit
  9. import AVFoundation
  10. import CoreMotion
  11. open class DKCameraPassthroughView: UIView {
  12. open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
  13. let hitTestingView = super.hitTest(point, with: event)
  14. return hitTestingView == self ? nil : hitTestingView
  15. }
  16. }
  17. extension AVMetadataFaceObject {
  18. open func realBounds(inCamera camera: DKCamera) -> CGRect {
  19. var bounds = CGRect()
  20. let previewSize = camera.previewLayer.bounds.size
  21. let isFront = camera.currentDevice == camera.captureDeviceFront
  22. if isFront {
  23. bounds.origin = CGPoint(x: previewSize.width - previewSize.width * (1 - self.bounds.origin.y - self.bounds.size.height / 2),
  24. y: previewSize.height * (self.bounds.origin.x + self.bounds.size.width / 2))
  25. } else {
  26. bounds.origin = CGPoint(x: previewSize.width * (1 - self.bounds.origin.y - self.bounds.size.height / 2),
  27. y: previewSize.height * (self.bounds.origin.x + self.bounds.size.width / 2))
  28. }
  29. bounds.size = CGSize(width: self.bounds.width * previewSize.height,
  30. height: self.bounds.height * previewSize.width)
  31. return bounds
  32. }
  33. }
  34. @objc
  35. public enum DKCameraDeviceSourceType : Int {
  36. case front, rear
  37. }
  38. open class DKCamera: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
  39. open class func checkCameraPermission(_ handler: @escaping (_ granted: Bool) -> Void) {
  40. func hasCameraPermission() -> Bool {
  41. return AVCaptureDevice.authorizationStatus(for: AVMediaType.video) == .authorized
  42. }
  43. func needsToRequestCameraPermission() -> Bool {
  44. return AVCaptureDevice.authorizationStatus(for: AVMediaType.video) == .notDetermined
  45. }
  46. hasCameraPermission() ? handler(true) : (needsToRequestCameraPermission() ?
  47. AVCaptureDevice.requestAccess(for: AVMediaType.video, completionHandler: { granted in
  48. DispatchQueue.main.async(execute: { () -> Void in
  49. hasCameraPermission() ? handler(true) : handler(false)
  50. })
  51. }) : handler(false))
  52. }
  53. open var didCancel: (() -> Void)?
  54. open var didFinishCapturingImage: ((_ image: UIImage) -> Void)?
  55. /// Notify the listener of the detected faces in the preview frame.
  56. open var onFaceDetection: ((_ faces: [AVMetadataFaceObject]) -> Void)?
  57. /// Be careful this may cause the view to load prematurely.
  58. open var cameraOverlayView: UIView? {
  59. didSet {
  60. if let cameraOverlayView = cameraOverlayView {
  61. self.view.addSubview(cameraOverlayView)
  62. }
  63. }
  64. }
  65. /// The flashModel will to be remembered to next use.
  66. open var flashMode:AVCaptureDevice.FlashMode! {
  67. didSet {
  68. self.updateFlashButton()
  69. self.updateFlashMode()
  70. self.updateFlashModeToUserDefautls(self.flashMode)
  71. }
  72. }
  73. open class func isAvailable() -> Bool {
  74. return UIImagePickerController.isSourceTypeAvailable(.camera)
  75. }
  76. /// Determines whether or not the rotation is enabled.
  77. open var allowsRotate = false
  78. /// set to NO to hide all standard camera UI. default is YES.
  79. open var showsCameraControls = true {
  80. didSet {
  81. self.contentView.isHidden = !self.showsCameraControls
  82. }
  83. }
  84. public let captureSession = AVCaptureSession()
  85. open var previewLayer: AVCaptureVideoPreviewLayer!
  86. fileprivate var beginZoomScale: CGFloat = 1.0
  87. fileprivate var zoomScale: CGFloat = 1.0
  88. open var defaultCaptureDevice = DKCameraDeviceSourceType.rear
  89. open var currentDevice: AVCaptureDevice?
  90. open var captureDeviceFront: AVCaptureDevice?
  91. open var captureDeviceRear: AVCaptureDevice?
  92. fileprivate weak var stillImageOutput: AVCaptureStillImageOutput?
  93. open var contentView = UIView()
  94. open var originalOrientation: UIDeviceOrientation!
  95. open var currentOrientation: UIDeviceOrientation!
  96. public let motionManager = CMMotionManager()
  97. open lazy var flashButton: UIButton = {
  98. let flashButton = UIButton()
  99. flashButton.addTarget(self, action: #selector(DKCamera.switchFlashMode), for: .touchUpInside)
  100. return flashButton
  101. }()
  102. open var cameraSwitchButton: UIButton!
  103. open var captureButton: UIButton!
  104. override open func viewDidLoad() {
  105. super.viewDidLoad()
  106. self.setupDevices()
  107. self.setupUI()
  108. self.setupSession()
  109. self.setupMotionManager()
  110. }
  111. open override func viewWillAppear(_ animated: Bool) {
  112. super.viewWillAppear(animated)
  113. if !self.captureSession.isRunning {
  114. self.captureSession.startRunning()
  115. }
  116. if !self.motionManager.isAccelerometerActive {
  117. self.motionManager.startAccelerometerUpdates(to: OperationQueue.current!, withHandler: { accelerometerData, error in
  118. if error == nil {
  119. let currentOrientation = accelerometerData!.acceleration.toDeviceOrientation() ?? self.currentOrientation
  120. if self.originalOrientation == nil {
  121. self.initialOriginalOrientationForOrientation()
  122. self.currentOrientation = self.originalOrientation
  123. }
  124. if let currentOrientation = currentOrientation , self.currentOrientation != currentOrientation {
  125. self.currentOrientation = currentOrientation
  126. self.updateContentLayoutForCurrentOrientation()
  127. }
  128. } else {
  129. print("error while update accelerometer: \(error!.localizedDescription)", terminator: "")
  130. }
  131. })
  132. }
  133. self.updateSession(isEnable: true)
  134. }
  135. open override func viewDidLayoutSubviews() {
  136. super.viewDidLayoutSubviews()
  137. if self.originalOrientation == nil {
  138. self.contentView.frame = self.view.bounds
  139. self.previewLayer.frame = self.view.bounds
  140. }
  141. }
  142. open override func viewDidDisappear(_ animated: Bool) {
  143. super.viewDidDisappear(animated)
  144. self.updateSession(isEnable: false)
  145. self.motionManager.stopAccelerometerUpdates()
  146. }
  147. override open func didReceiveMemoryWarning() {
  148. super.didReceiveMemoryWarning()
  149. // Dispose of any resources that can be recreated.
  150. }
  151. open override var prefersStatusBarHidden : Bool {
  152. return true
  153. }
  154. // MARK: - Setup
  155. let bottomView = UIView()
  156. open func setupUI() {
  157. self.view.backgroundColor = UIColor.black
  158. self.view.addSubview(self.contentView)
  159. self.contentView.backgroundColor = UIColor.clear
  160. self.contentView.frame = self.view.bounds
  161. let bottomViewHeight: CGFloat = 70
  162. bottomView.bounds.size = CGSize(width: contentView.bounds.width, height: bottomViewHeight)
  163. bottomView.frame.origin = CGPoint(x: 0, y: contentView.bounds.height - bottomViewHeight)
  164. bottomView.autoresizingMask = [.flexibleWidth, .flexibleTopMargin]
  165. bottomView.backgroundColor = UIColor(white: 0, alpha: 0.4)
  166. contentView.addSubview(bottomView)
  167. // switch button
  168. let cameraSwitchButton: UIButton = {
  169. let cameraSwitchButton = UIButton()
  170. cameraSwitchButton.addTarget(self, action: #selector(DKCamera.switchCamera), for: .touchUpInside)
  171. cameraSwitchButton.setImage(DKCameraResource.cameraSwitchImage(), for: .normal)
  172. cameraSwitchButton.sizeToFit()
  173. return cameraSwitchButton
  174. }()
  175. cameraSwitchButton.frame.origin = CGPoint(x: bottomView.bounds.width - cameraSwitchButton.bounds.width - 15,
  176. y: (bottomView.bounds.height - cameraSwitchButton.bounds.height) / 2)
  177. cameraSwitchButton.autoresizingMask = [.flexibleLeftMargin, .flexibleTopMargin, .flexibleBottomMargin]
  178. bottomView.addSubview(cameraSwitchButton)
  179. self.cameraSwitchButton = cameraSwitchButton
  180. // capture button
  181. let captureButton: UIButton = {
  182. class DKCaptureButton: UIButton {
  183. fileprivate override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
  184. self.backgroundColor = UIColor.white
  185. return true
  186. }
  187. fileprivate override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
  188. self.backgroundColor = UIColor.white
  189. return true
  190. }
  191. fileprivate override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
  192. self.backgroundColor = nil
  193. }
  194. fileprivate override func cancelTracking(with event: UIEvent?) {
  195. self.backgroundColor = nil
  196. }
  197. }
  198. let captureButton = DKCaptureButton()
  199. captureButton.addTarget(self, action: #selector(DKCamera.takePicture), for: .touchUpInside)
  200. captureButton.bounds.size = CGSize(width: bottomViewHeight,
  201. height: bottomViewHeight).applying(CGAffineTransform(scaleX: 0.9, y: 0.9))
  202. captureButton.layer.cornerRadius = captureButton.bounds.height / 2
  203. captureButton.layer.borderColor = UIColor.white.cgColor
  204. captureButton.layer.borderWidth = 2
  205. captureButton.layer.masksToBounds = true
  206. return captureButton
  207. }()
  208. captureButton.center = CGPoint(x: bottomView.bounds.width / 2, y: bottomView.bounds.height / 2)
  209. captureButton.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin]
  210. bottomView.addSubview(captureButton)
  211. self.captureButton = captureButton
  212. // cancel button
  213. let cancelButton: UIButton = {
  214. let cancelButton = UIButton()
  215. cancelButton.addTarget(self, action: #selector(dismiss as () -> Void), for: .touchUpInside)
  216. cancelButton.setImage(DKCameraResource.cameraCancelImage(), for: .normal)
  217. cancelButton.sizeToFit()
  218. return cancelButton
  219. }()
  220. cancelButton.frame.origin = CGPoint(x: contentView.bounds.width - cancelButton.bounds.width - 15, y: 25)
  221. cancelButton.autoresizingMask = [.flexibleBottomMargin, .flexibleLeftMargin]
  222. contentView.addSubview(cancelButton)
  223. self.flashButton.frame.origin = CGPoint(x: 5, y: 15)
  224. contentView.addSubview(self.flashButton)
  225. contentView.addGestureRecognizer(UIPinchGestureRecognizer(target: self, action: #selector(DKCamera.handleZoom(_:))))
  226. contentView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(DKCamera.handleFocus(_:))))
  227. }
  228. open func setupSession() {
  229. self.captureSession.sessionPreset = AVCaptureSession.Preset.photo
  230. self.setupCurrentDevice()
  231. let stillImageOutput = AVCaptureStillImageOutput()
  232. if self.captureSession.canAddOutput(stillImageOutput) {
  233. self.captureSession.addOutput(stillImageOutput)
  234. self.stillImageOutput = stillImageOutput
  235. }
  236. if self.onFaceDetection != nil {
  237. let metadataOutput = AVCaptureMetadataOutput()
  238. metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue(label: "MetadataOutputQueue"))
  239. if self.captureSession.canAddOutput(metadataOutput) {
  240. self.captureSession.addOutput(metadataOutput)
  241. metadataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.face]
  242. }
  243. }
  244. self.previewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession)
  245. self.previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
  246. self.previewLayer.frame = self.view.bounds
  247. let rootLayer = self.view.layer
  248. rootLayer.masksToBounds = true
  249. rootLayer.insertSublayer(self.previewLayer, at: 0)
  250. }
  251. open func setupCurrentDevice() {
  252. if let currentDevice = self.currentDevice {
  253. if currentDevice.isFlashAvailable {
  254. self.flashButton.isHidden = false
  255. self.flashMode = self.flashModeFromUserDefaults()
  256. } else {
  257. self.flashButton.isHidden = true
  258. }
  259. for oldInput in self.captureSession.inputs {
  260. self.captureSession.removeInput(oldInput)
  261. }
  262. let frontInput = try? AVCaptureDeviceInput(device: self.currentDevice!)
  263. if self.captureSession.canAddInput(frontInput!) {
  264. self.captureSession.addInput(frontInput!)
  265. }
  266. try! currentDevice.lockForConfiguration()
  267. if currentDevice.isFocusModeSupported(.continuousAutoFocus) {
  268. currentDevice.focusMode = .continuousAutoFocus
  269. }
  270. if currentDevice.isExposureModeSupported(.continuousAutoExposure) {
  271. currentDevice.exposureMode = .continuousAutoExposure
  272. }
  273. currentDevice.unlockForConfiguration()
  274. }
  275. }
  276. open func setupDevices() {
  277. let devices = AVCaptureDevice.devices(for: AVMediaType.video)
  278. for device in devices {
  279. if device.position == .back {
  280. self.captureDeviceRear = device
  281. }
  282. if device.position == .front {
  283. self.captureDeviceFront = device
  284. }
  285. }
  286. switch self.defaultCaptureDevice {
  287. case .front:
  288. self.currentDevice = self.captureDeviceFront ?? self.captureDeviceRear
  289. case .rear:
  290. self.currentDevice = self.captureDeviceRear ?? self.captureDeviceFront
  291. }
  292. }
  293. // MARK: - Session
  294. fileprivate var isStopped = false
  295. open func startSession() {
  296. self.isStopped = false
  297. if !self.captureSession.isRunning {
  298. self.captureSession.startRunning()
  299. }
  300. }
  301. open func stopSession() {
  302. self.pauseSession()
  303. self.captureSession.stopRunning()
  304. }
  305. open func pauseSession() {
  306. self.isStopped = true
  307. self.updateSession(isEnable: false)
  308. }
  309. open func updateSession(isEnable: Bool) {
  310. if ((!self.isStopped) || (self.isStopped && !isEnable)),
  311. let connection = self.previewLayer.connection {
  312. connection.isEnabled = isEnable
  313. }
  314. }
  315. // MARK: - Callbacks
  316. @objc internal func dismiss() {
  317. self.didCancel?()
  318. }
  319. @objc open func takePicture() {
  320. let authStatus = AVCaptureDevice.authorizationStatus(for: AVMediaType.video)
  321. if authStatus == .denied {
  322. return
  323. }
  324. if let stillImageOutput = self.stillImageOutput, !stillImageOutput.isCapturingStillImage {
  325. self.captureButton.isEnabled = false
  326. DispatchQueue.global().async(execute: {
  327. if let connection = stillImageOutput.connection(with: AVMediaType.video) {
  328. connection.videoOrientation = self.currentOrientation.toAVCaptureVideoOrientation()
  329. connection.videoScaleAndCropFactor = self.zoomScale
  330. stillImageOutput.captureStillImageAsynchronously(from: connection, completionHandler: { (imageDataSampleBuffer, error) in
  331. if error == nil {
  332. let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer!)
  333. if let didFinishCapturingImage = self.didFinishCapturingImage, let imageData = imageData, let takenImage = UIImage(data: imageData) {
  334. let outputRect = self.previewLayer.metadataOutputRectConverted(fromLayerRect: self.previewLayer.bounds)
  335. let takenCGImage = takenImage.cgImage!
  336. let width = CGFloat(takenCGImage.width)
  337. let height = CGFloat(takenCGImage.height)
  338. let cropRect = CGRect(x: outputRect.origin.x * width, y: outputRect.origin.y * height, width: outputRect.size.width * width, height: outputRect.size.height * height)
  339. let cropCGImage = takenCGImage.cropping(to: cropRect)
  340. let cropTakenImage = UIImage(cgImage: cropCGImage!, scale: 1, orientation: takenImage.imageOrientation)
  341. didFinishCapturingImage(cropTakenImage)
  342. self.captureButton.isEnabled = true
  343. }
  344. } else {
  345. print("error while capturing still image: \(error!.localizedDescription)", terminator: "")
  346. }
  347. })
  348. }
  349. })
  350. }
  351. }
  352. // MARK: - Handles Zoom
  353. @objc open func handleZoom(_ gesture: UIPinchGestureRecognizer) {
  354. if gesture.state == .began {
  355. self.beginZoomScale = self.zoomScale
  356. } else if gesture.state == .changed {
  357. self.zoomScale = min(4.0, max(1.0, self.beginZoomScale * gesture.scale))
  358. CATransaction.begin()
  359. CATransaction.setAnimationDuration(0.025)
  360. self.previewLayer.setAffineTransform(CGAffineTransform(scaleX: self.zoomScale, y: self.zoomScale))
  361. CATransaction.commit()
  362. }
  363. }
  364. // MARK: - Handles Focus
  365. @objc open func handleFocus(_ gesture: UITapGestureRecognizer) {
  366. if let currentDevice = self.currentDevice , currentDevice.isFocusPointOfInterestSupported {
  367. let touchPoint = gesture.location(in: self.view)
  368. self.focusAtTouchPoint(touchPoint)
  369. }
  370. }
  371. open func focusAtTouchPoint(_ touchPoint: CGPoint) {
  372. func showFocusViewAtPoint(_ touchPoint: CGPoint) {
  373. struct FocusView {
  374. static let focusView: UIView = {
  375. let focusView = UIView()
  376. let diameter: CGFloat = 100
  377. focusView.bounds.size = CGSize(width: diameter, height: diameter)
  378. focusView.layer.borderWidth = 2
  379. focusView.layer.cornerRadius = diameter / 2
  380. focusView.layer.borderColor = UIColor.white.cgColor
  381. return focusView
  382. }()
  383. }
  384. FocusView.focusView.transform = CGAffineTransform.identity
  385. FocusView.focusView.center = touchPoint
  386. self.view.addSubview(FocusView.focusView)
  387. UIView.animate(withDuration: 0.7, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 1.1,
  388. options: UIView.AnimationOptions(), animations: { () -> Void in
  389. FocusView.focusView.transform = CGAffineTransform.identity.scaledBy(x: 0.6, y: 0.6)
  390. }) { (Bool) -> Void in
  391. FocusView.focusView.removeFromSuperview()
  392. }
  393. }
  394. if self.currentDevice == nil || self.currentDevice?.isFlashAvailable == false {
  395. return
  396. }
  397. let focusPoint = self.previewLayer.captureDevicePointConverted(fromLayerPoint: touchPoint)
  398. showFocusViewAtPoint(touchPoint)
  399. if let currentDevice = self.currentDevice {
  400. try! currentDevice.lockForConfiguration()
  401. currentDevice.focusPointOfInterest = focusPoint
  402. currentDevice.exposurePointOfInterest = focusPoint
  403. currentDevice.focusMode = .continuousAutoFocus
  404. if currentDevice.isExposureModeSupported(.continuousAutoExposure) {
  405. currentDevice.exposureMode = .continuousAutoExposure
  406. }
  407. currentDevice.unlockForConfiguration()
  408. }
  409. }
  410. // MARK: - Handles Switch Camera
  411. @objc internal func switchCamera() {
  412. self.currentDevice = self.currentDevice == self.captureDeviceRear ?
  413. self.captureDeviceFront : self.captureDeviceRear
  414. self.setupCurrentDevice()
  415. }
  416. // MARK: - Handles Flash
  417. @objc internal func switchFlashMode() {
  418. switch self.flashMode! {
  419. case .auto:
  420. self.flashMode = .off
  421. case .on:
  422. self.flashMode = .auto
  423. case .off:
  424. self.flashMode = .on
  425. }
  426. }
  427. open func flashModeFromUserDefaults() -> AVCaptureDevice.FlashMode {
  428. let rawValue = UserDefaults.standard.integer(forKey: "DKCamera.flashMode")
  429. return AVCaptureDevice.FlashMode(rawValue: rawValue)!
  430. }
  431. open func updateFlashModeToUserDefautls(_ flashMode: AVCaptureDevice.FlashMode) {
  432. UserDefaults.standard.set(flashMode.rawValue, forKey: "DKCamera.flashMode")
  433. }
  434. open func updateFlashButton() {
  435. struct FlashImage {
  436. static let images = [
  437. AVCaptureDevice.FlashMode.auto : DKCameraResource.cameraFlashAutoImage(),
  438. AVCaptureDevice.FlashMode.on : DKCameraResource.cameraFlashOnImage(),
  439. AVCaptureDevice.FlashMode.off : DKCameraResource.cameraFlashOffImage()
  440. ]
  441. }
  442. let flashImage: UIImage = FlashImage.images[self.flashMode]!
  443. self.flashButton.setImage(flashImage, for: .normal)
  444. self.flashButton.sizeToFit()
  445. }
  446. open func updateFlashMode() {
  447. if let currentDevice = self.currentDevice
  448. , currentDevice.isFlashAvailable && currentDevice.isFlashModeSupported(self.flashMode) {
  449. try! currentDevice.lockForConfiguration()
  450. currentDevice.flashMode = self.flashMode
  451. currentDevice.unlockForConfiguration()
  452. }
  453. }
  454. // MARK: - AVCaptureMetadataOutputObjectsDelegate
  455. public func metadataOutput(_ captureOutput: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
  456. self.onFaceDetection?(metadataObjects as! [AVMetadataFaceObject])
  457. }
  458. // MARK: - Handles Orientation
  459. open override var shouldAutorotate : Bool {
  460. return false
  461. }
  462. open func setupMotionManager() {
  463. self.motionManager.accelerometerUpdateInterval = 0.5
  464. self.motionManager.gyroUpdateInterval = 0.5
  465. }
  466. open func initialOriginalOrientationForOrientation() {
  467. self.originalOrientation = UIApplication.shared.statusBarOrientation.toDeviceOrientation()
  468. if let connection = self.previewLayer.connection {
  469. connection.videoOrientation = self.originalOrientation.toAVCaptureVideoOrientation()
  470. }
  471. }
  472. open func updateContentLayoutForCurrentOrientation() {
  473. let newAngle = self.currentOrientation.toAngleRelativeToPortrait() - self.originalOrientation.toAngleRelativeToPortrait()
  474. if self.allowsRotate {
  475. var contentViewNewSize: CGSize!
  476. let width = self.view.bounds.width
  477. let height = self.view.bounds.height
  478. if self.currentOrientation.isLandscape {
  479. contentViewNewSize = CGSize(width: max(width, height), height: min(width, height))
  480. } else {
  481. contentViewNewSize = CGSize(width: min(width, height), height: max(width, height))
  482. }
  483. UIView.animate(withDuration: 0.2, animations: {
  484. self.contentView.bounds.size = contentViewNewSize
  485. self.contentView.transform = CGAffineTransform(rotationAngle: newAngle)
  486. })
  487. } else {
  488. let rotateAffineTransform = CGAffineTransform.identity.rotated(by: newAngle)
  489. UIView.animate(withDuration: 0.2, animations: {
  490. self.flashButton.transform = rotateAffineTransform
  491. self.cameraSwitchButton.transform = rotateAffineTransform
  492. })
  493. }
  494. }
  495. }
  496. // MARK: - Utilities
  497. public extension UIInterfaceOrientation {
  498. func toDeviceOrientation() -> UIDeviceOrientation {
  499. switch self {
  500. case .portrait:
  501. return .portrait
  502. case .portraitUpsideDown:
  503. return .portraitUpsideDown
  504. case .landscapeRight:
  505. return .landscapeLeft
  506. case .landscapeLeft:
  507. return .landscapeRight
  508. default:
  509. return .portrait
  510. }
  511. }
  512. }
  513. public extension UIDeviceOrientation {
  514. func toAVCaptureVideoOrientation() -> AVCaptureVideoOrientation {
  515. switch self {
  516. case .portrait:
  517. return .portrait
  518. case .portraitUpsideDown:
  519. return .portraitUpsideDown
  520. case .landscapeRight:
  521. return .landscapeLeft
  522. case .landscapeLeft:
  523. return .landscapeRight
  524. default:
  525. return .portrait
  526. }
  527. }
  528. func toInterfaceOrientationMask() -> UIInterfaceOrientationMask {
  529. switch self {
  530. case .portrait:
  531. return .portrait
  532. case .portraitUpsideDown:
  533. return .portraitUpsideDown
  534. case .landscapeRight:
  535. return .landscapeLeft
  536. case .landscapeLeft:
  537. return .landscapeRight
  538. default:
  539. return .portrait
  540. }
  541. }
  542. func toAngleRelativeToPortrait() -> CGFloat {
  543. switch self {
  544. case .portrait:
  545. return 0
  546. case .portraitUpsideDown:
  547. return CGFloat.pi
  548. case .landscapeRight:
  549. return -CGFloat.pi / 2.0
  550. case .landscapeLeft:
  551. return CGFloat.pi / 2.0
  552. default:
  553. return 0.0
  554. }
  555. }
  556. }
  557. public extension CMAcceleration {
  558. func toDeviceOrientation() -> UIDeviceOrientation? {
  559. if self.x >= 0.75 {
  560. return .landscapeRight
  561. } else if self.x <= -0.75 {
  562. return .landscapeLeft
  563. } else if self.y <= -0.75 {
  564. return .portrait
  565. } else if self.y >= 0.75 {
  566. return .portraitUpsideDown
  567. } else {
  568. return nil
  569. }
  570. }
  571. }
  572. // MARK: - Rersources
  573. public extension Bundle {
  574. class func cameraBundle() -> Bundle {
  575. let assetPath = Bundle(for: DKCameraResource.self).resourcePath!
  576. return Bundle(path: (assetPath as NSString).appendingPathComponent("DKCameraResource.bundle"))!
  577. }
  578. }
  579. open class DKCameraResource {
  580. open class func imageForResource(_ name: String) -> UIImage {
  581. let bundle = Bundle.cameraBundle()
  582. let imagePath = bundle.path(forResource: name, ofType: "png", inDirectory: "Images")
  583. let image = UIImage(contentsOfFile: imagePath!)
  584. return image!
  585. }
  586. class func cameraCancelImage() -> UIImage {
  587. return imageForResource("camera_cancel")
  588. }
  589. class func cameraFlashOnImage() -> UIImage {
  590. return imageForResource("camera_flash_on")
  591. }
  592. class func cameraFlashAutoImage() -> UIImage {
  593. return imageForResource("camera_flash_auto")
  594. }
  595. class func cameraFlashOffImage() -> UIImage {
  596. return imageForResource("camera_flash_off")
  597. }
  598. class func cameraSwitchImage() -> UIImage {
  599. return imageForResource("camera_switch")
  600. }
  601. }