-
Notifications
You must be signed in to change notification settings - Fork 5
Multi orientation support #185
Changes from all commits
34382ce
4706f29
bff4392
d772f3a
aad4e11
ddf23a0
5aa5e7d
8b0c35a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -14,21 +14,24 @@ extension AVCaptureVideoOrientation { | |||
| /// Maps UIDeviceOrientation to AVCaptureVideoOrientation | ||||
| init?(deviceOrientation: UIDeviceOrientation) { | ||||
| switch deviceOrientation { | ||||
| case .portrait: | ||||
| self.init(rawValue: AVCaptureVideoOrientation.portrait.rawValue) | ||||
| case .portraitUpsideDown: | ||||
| self.init(rawValue: AVCaptureVideoOrientation.portraitUpsideDown.rawValue) | ||||
| case .landscapeLeft: | ||||
| self.init(rawValue: AVCaptureVideoOrientation.landscapeLeft.rawValue) | ||||
| case .landscapeRight: | ||||
| self.init(rawValue: AVCaptureVideoOrientation.landscapeRight.rawValue) | ||||
| case .faceUp: | ||||
| self.init(rawValue: AVCaptureVideoOrientation.portrait.rawValue) | ||||
| case .faceDown: | ||||
| self.init(rawValue: AVCaptureVideoOrientation.portraitUpsideDown.rawValue) | ||||
| default: | ||||
| self.init(rawValue: AVCaptureVideoOrientation.portrait.rawValue) | ||||
| case .portrait: self = .portrait | ||||
| case .portraitUpsideDown: self = .portraitUpsideDown | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| case .landscapeLeft: self = .landscapeLeft | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| case .landscapeRight: self = .landscapeRight | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| case .faceUp: self = .portrait | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| case .faceDown: self = .portraitUpsideDown | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| default: self = .portrait | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| } | ||||
| } | ||||
|
|
||||
| /// Maps UIInterfaceOrientation to AVCaptureVideoOrientation | ||||
| init?(interfaceOrientation: UIInterfaceOrientation) { | ||||
| switch interfaceOrientation { | ||||
| case .portrait: self = .portrait | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| case .portraitUpsideDown: self = .portraitUpsideDown | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| case .landscapeLeft: self = .landscapeLeft | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| case .landscapeRight: self = .landscapeRight | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| default: return nil | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| } | ||||
| } | ||||
|
|
||||
| } | ||||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -31,4 +31,32 @@ extension CGImagePropertyOrientation { | |||
| self = .right | ||||
| } | ||||
| } | ||||
|
|
||||
| init(deviceOrientation: UIDeviceOrientation) { | ||||
| switch deviceOrientation { | ||||
| case .portrait: self = .up | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| case .portraitUpsideDown: self = .down | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| case .landscapeLeft: self = .left | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| case .landscapeRight: self = .right | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| case .unknown: self = .up | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| case .faceUp: self = .up | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| case .faceDown: self = .up | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| @unknown default: | ||||
| assertionFailure("Unknow orientation, falling to default") | ||||
| self = .right | ||||
| } | ||||
| } | ||||
|
|
||||
| init(interfaceOrientation: UIInterfaceOrientation) { | ||||
| switch interfaceOrientation { | ||||
| case .portrait: self = .up | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| case .portraitUpsideDown: self = .up | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| case .landscapeLeft: self = .left | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| case .landscapeRight: self = .right | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| case .unknown: self = .up | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| @unknown default: | ||||
| assertionFailure("Unknow orientation, falling to default") | ||||
| self = .right | ||||
| } | ||||
| } | ||||
| } | ||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| // | ||
| // UIInterfaceOrientation+Utils.swift | ||
| // WeScan | ||
| // | ||
| // Created by Antoine Harlin on 01/10/2019. | ||
| // Copyright © 2019 WeTransfer. All rights reserved. | ||
| // | ||
|
|
||
| import Foundation | ||
| import UIKit | ||
|
|
||
| extension UIInterfaceOrientation { | ||
| var rotationAngle: CGFloat { | ||
| switch self { | ||
| case UIInterfaceOrientation.portrait: | ||
| return CGFloat.pi / 2 | ||
| case UIInterfaceOrientation.portraitUpsideDown: | ||
| return -CGFloat.pi / 2 | ||
| case UIInterfaceOrientation.landscapeLeft: | ||
| return CGFloat.pi | ||
| case UIInterfaceOrientation.landscapeRight: | ||
| return CGFloat.pi * 2 | ||
| default: | ||
| return CGFloat.pi / 2 | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -102,17 +102,23 @@ final class ScannerViewController: UIViewController { | |||
| navigationController?.navigationBar.sendSubviewToBack(visualEffectView) | ||||
|
|
||||
| navigationController?.navigationBar.barStyle = .blackTranslucent | ||||
|
|
||||
| setupVideoOrientation() | ||||
| setupViewsForCurrentOrientation() | ||||
| } | ||||
|
|
||||
| override func viewDidLayoutSubviews() { | ||||
| super.viewDidLayoutSubviews() | ||||
|
|
||||
| videoPreviewLayer.frame = view.layer.bounds | ||||
|
|
||||
| let statusBarHeight = UIApplication.shared.statusBarFrame.size.height | ||||
| let visualEffectRect = self.navigationController?.navigationBar.bounds.insetBy(dx: 0, dy: -(statusBarHeight)).offsetBy(dx: 0, dy: -statusBarHeight) | ||||
|
|
||||
| visualEffectView.frame = visualEffectRect ?? CGRect.zero | ||||
|
|
||||
| override func viewDidAppear(_ animated: Bool) { | ||||
| super.viewDidAppear(animated) | ||||
| setupViewsForCurrentOrientation() | ||||
| } | ||||
|
|
||||
| override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { | ||||
| super.viewWillTransition(to: size, with: coordinator) | ||||
| coordinator.animate(alongsideTransition: { [weak self] (context) in | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||
| self?.setupViewsForCurrentOrientation() | ||||
| }, completion: { [weak self] (_) in | ||||
| self?.setupVideoOrientation() | ||||
| }) | ||||
| } | ||||
|
|
||||
| override func viewWillDisappear(_ animated: Bool) { | ||||
|
|
@@ -140,7 +146,20 @@ final class ScannerViewController: UIViewController { | |||
| view.addSubview(shutterButton) | ||||
| view.addSubview(activityIndicator) | ||||
| } | ||||
|
|
||||
|
|
||||
| private func setupViewsForCurrentOrientation() { | ||||
| let statusBarHeight = UIApplication.shared.statusBarFrame.size.height | ||||
| let visualEffectRect = self.navigationController?.navigationBar.bounds.insetBy( | ||||
| dx: 0, | ||||
| dy: -(statusBarHeight) | ||||
| ).offsetBy( | ||||
| dx: 0, | ||||
| dy: -statusBarHeight | ||||
| ) | ||||
| self.visualEffectView.frame = visualEffectRect ?? CGRect.zero | ||||
| videoPreviewLayer.frame = view.layer.bounds | ||||
| } | ||||
|
|
||||
| private func setupNavigationBar() { | ||||
| navigationItem.setLeftBarButton(flashButton, animated: false) | ||||
| navigationItem.setRightBarButton(autoScanButton, animated: false) | ||||
|
|
@@ -196,6 +215,17 @@ final class ScannerViewController: UIViewController { | |||
|
|
||||
| NSLayoutConstraint.activate(quadViewConstraints + cancelButtonConstraints + shutterButtonConstraints + activityIndicatorConstraints) | ||||
| } | ||||
|
|
||||
| func setupVideoOrientation() { | ||||
| let statusBarOrientation = UIApplication.shared.statusBarOrientation | ||||
| var initialVideoOrientation: AVCaptureVideoOrientation = .portrait | ||||
| if statusBarOrientation != .unknown { | ||||
| if let videoOrientation = AVCaptureVideoOrientation(rawValue: statusBarOrientation.rawValue) { | ||||
| initialVideoOrientation = videoOrientation | ||||
| } | ||||
| } | ||||
| videoPreviewLayer.connection?.videoOrientation = initialVideoOrientation | ||||
| } | ||||
|
|
||||
| // MARK: - Tap to Focus | ||||
|
|
||||
|
|
@@ -302,7 +332,6 @@ extension ScannerViewController: RectangleDetectionDelegateProtocol { | |||
|
|
||||
| func captureSessionManager(_ captureSessionManager: CaptureSessionManager, didCapturePicture picture: UIImage, withQuad quad: Quadrilateral?) { | ||||
| activityIndicator.stopAnimating() | ||||
|
|
||||
| let editVC = EditScanViewController(image: picture, quad: quad) | ||||
| navigationController?.pushViewController(editVC, animated: false) | ||||
|
|
||||
|
|
@@ -315,13 +344,18 @@ extension ScannerViewController: RectangleDetectionDelegateProtocol { | |||
| quadView.removeQuadrilateral() | ||||
| return | ||||
| } | ||||
|
|
||||
| let statusBarOrientation = UIApplication.shared.statusBarOrientation | ||||
|
|
||||
| let orientedImageSize = CGSize( | ||||
| width: statusBarOrientation.isPortrait ? imageSize.height : imageSize.width, | ||||
| height: statusBarOrientation.isPortrait ? imageSize.width : imageSize.height | ||||
| ) | ||||
|
|
||||
| let portraitImageSize = CGSize(width: imageSize.height, height: imageSize.width) | ||||
|
|
||||
| let scaleTransform = CGAffineTransform.scaleTransform(forSize: portraitImageSize, aspectFillInSize: quadView.bounds.size) | ||||
| let scaleTransform = CGAffineTransform.scaleTransform(forSize: orientedImageSize, aspectFillInSize: quadView.bounds.size) | ||||
| let scaledImageSize = imageSize.applying(scaleTransform) | ||||
|
|
||||
| let rotationTransform = CGAffineTransform(rotationAngle: CGFloat.pi / 2.0) | ||||
| let rotationTransform = CGAffineTransform(rotationAngle: statusBarOrientation.rotationAngle) | ||||
|
|
||||
| let imageBounds = CGRect(origin: .zero, size: scaledImageSize).applying(rotationTransform) | ||||
|
|
||||
|
|
||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.