From 04faa034e30a5093cff95e8c4bad4148872c6c8e Mon Sep 17 00:00:00 2001 From: Jon Andersen Date: Thu, 7 Sep 2017 17:00:18 -0400 Subject: [PATCH] Move orientation logic to separate class --- Source/Orientation.swift | 94 ++++++++++++++++++++++++++++ Source/SwiftyCamViewController.swift | 72 +++------------------ 2 files changed, 101 insertions(+), 65 deletions(-) create mode 100644 Source/Orientation.swift diff --git a/Source/Orientation.swift b/Source/Orientation.swift new file mode 100644 index 0000000..de74816 --- /dev/null +++ b/Source/Orientation.swift @@ -0,0 +1,94 @@ +/*Copyright (c) 2016, Andrew Walz. + + Redistribution and use in source and binary forms, with or without modification,are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +import Foundation +import AVFoundation +import UIKit + +protocol Orientation: class { + func getPreviewLayerOrientation() -> AVCaptureVideoOrientation + func getVideoOrientation() -> AVCaptureVideoOrientation? + func getImageOrientation(forCamera: SwiftyCamViewController.CameraSelection) -> UIImageOrientation + func start() + func stop() +} + +class DeviceOrientation : Orientation { + var deviceOrientation : UIDeviceOrientation? + var shouldUseDeviceOrientation: Bool = false + + func start() { + self.deviceOrientation = UIDevice.current.orientation + NotificationCenter.default.addObserver(self, selector: #selector(didRotate), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) + } + + func stop() { + NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) + self.deviceOrientation = nil + } + + @objc func didRotate() { + if !UIDevice.current.orientation.isFlat { + self.deviceOrientation = UIDevice.current.orientation + } + } + + func getImageOrientation(forCamera: SwiftyCamViewController.CameraSelection) -> UIImageOrientation { + guard shouldUseDeviceOrientation, let deviceOrientation = self.deviceOrientation else { return forCamera == .rear ? .right : .leftMirrored } + + switch deviceOrientation { + case .landscapeLeft: + return forCamera == .rear ? .up : .downMirrored + case .landscapeRight: + return forCamera == .rear ? .down : .upMirrored + case .portraitUpsideDown: + return forCamera == .rear ? .left : .rightMirrored + default: + return forCamera == .rear ? .right : .leftMirrored + } + } + + func getPreviewLayerOrientation() -> AVCaptureVideoOrientation { + // Depends on layout orientation, not device orientation + switch UIApplication.shared.statusBarOrientation { + case .portrait, .unknown: + return AVCaptureVideoOrientation.portrait + case .landscapeLeft: + return AVCaptureVideoOrientation.landscapeLeft + case .landscapeRight: + return AVCaptureVideoOrientation.landscapeRight + case .portraitUpsideDown: + return AVCaptureVideoOrientation.portraitUpsideDown + } + } + + func getVideoOrientation() -> AVCaptureVideoOrientation? { + guard shouldUseDeviceOrientation, let deviceOrientation = self.deviceOrientation else { return nil } + + switch deviceOrientation { + case .landscapeLeft: + return .landscapeRight + case .landscapeRight: + return .landscapeLeft + case .portraitUpsideDown: + return .portraitUpsideDown + default: + return .portrait + } + } +} + + + diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift index 4a7e743..7a8cc77 100644 --- a/Source/SwiftyCamViewController.swift +++ b/Source/SwiftyCamViewController.swift @@ -233,7 +233,7 @@ open class SwiftyCamViewController: UIViewController { /// PreviewView for the capture session - fileprivate var previewLayer : PreviewView! + var previewLayer : PreviewView! /// UIView for front facing flash @@ -245,7 +245,7 @@ open class SwiftyCamViewController: UIViewController { /// Last changed orientation - fileprivate var deviceOrientation : UIDeviceOrientation? + var orientation : Orientation = DeviceOrientation() /// Boolean to store when View Controller is notified session is running @@ -368,7 +368,7 @@ open class SwiftyCamViewController: UIViewController { // Subscribe to device rotation notifications if shouldUseDeviceOrientation { - subscribeToDeviceOrientationChangeNotifications() + orientation.start() } // Set background audio preference @@ -384,7 +384,7 @@ open class SwiftyCamViewController: UIViewController { // Preview layer video orientation can be set only after the connection is created DispatchQueue.main.async { - self.previewLayer.videoPreviewLayer.connection?.videoOrientation = self.getPreviewLayerOrientation() + self.previewLayer.videoPreviewLayer.connection?.videoOrientation = self.orientation.getPreviewLayerOrientation() } case .notAuthorized: @@ -424,7 +424,7 @@ open class SwiftyCamViewController: UIViewController { // Unsubscribe from device rotation notifications if shouldUseDeviceOrientation { - unsubscribeFromDeviceOrientationChangeNotifications() + orientation.stop() } } @@ -519,7 +519,7 @@ open class SwiftyCamViewController: UIViewController { movieFileOutputConnection?.isVideoMirrored = true } - movieFileOutputConnection?.videoOrientation = self.getVideoOrientation() + movieFileOutputConnection?.videoOrientation = self.orientation.getVideoOrientation() ?? self.previewLayer.videoPreviewLayer.connection!.videoOrientation // Start recording to a temporary file. let outputFileName = UUID().uuidString @@ -776,65 +776,7 @@ open class SwiftyCamViewController: UIViewController { /// Orientation management - fileprivate func subscribeToDeviceOrientationChangeNotifications() { - self.deviceOrientation = UIDevice.current.orientation - NotificationCenter.default.addObserver(self, selector: #selector(deviceDidRotate), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) - } - fileprivate func unsubscribeFromDeviceOrientationChangeNotifications() { - NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) - self.deviceOrientation = nil - } - - @objc fileprivate func deviceDidRotate() { - if !UIDevice.current.orientation.isFlat { - self.deviceOrientation = UIDevice.current.orientation - } - } - - fileprivate func getPreviewLayerOrientation() -> AVCaptureVideoOrientation { - // Depends on layout orientation, not device orientation - switch UIApplication.shared.statusBarOrientation { - case .portrait, .unknown: - return AVCaptureVideoOrientation.portrait - case .landscapeLeft: - return AVCaptureVideoOrientation.landscapeLeft - case .landscapeRight: - return AVCaptureVideoOrientation.landscapeRight - case .portraitUpsideDown: - return AVCaptureVideoOrientation.portraitUpsideDown - } - } - - fileprivate func getVideoOrientation() -> AVCaptureVideoOrientation { - guard shouldUseDeviceOrientation, let deviceOrientation = self.deviceOrientation else { return previewLayer!.videoPreviewLayer.connection!.videoOrientation } - - switch deviceOrientation { - case .landscapeLeft: - return .landscapeRight - case .landscapeRight: - return .landscapeLeft - case .portraitUpsideDown: - return .portraitUpsideDown - default: - return .portrait - } - } - - fileprivate func getImageOrientation(forCamera: CameraSelection) -> UIImageOrientation { - guard shouldUseDeviceOrientation, let deviceOrientation = self.deviceOrientation else { return forCamera == .rear ? .right : .leftMirrored } - - switch deviceOrientation { - case .landscapeLeft: - return forCamera == .rear ? .up : .downMirrored - case .landscapeRight: - return forCamera == .rear ? .down : .upMirrored - case .portraitUpsideDown: - return forCamera == .rear ? .left : .rightMirrored - default: - return forCamera == .rear ? .right : .leftMirrored - } - } /** Returns a UIImage from Image Data. @@ -851,7 +793,7 @@ open class SwiftyCamViewController: UIViewController { // Set proper orientation for photo // If camera is currently set to front camera, flip image - let image = UIImage(cgImage: cgImageRef!, scale: 1.0, orientation: self.getImageOrientation(forCamera: self.currentCamera)) + let image = UIImage(cgImage: cgImageRef!, scale: 1.0, orientation: self.orientation.getImageOrientation(forCamera: self.currentCamera)) return image }