Update models

This commit is contained in:
Christoph
2018-08-16 11:18:27 +02:00
parent 2048bac6e9
commit 8ed9a6046d
46 changed files with 1656 additions and 69 deletions

View File

@ -0,0 +1,142 @@
//
// CameraController.swift
// CapFinder
//
// Created by User on 22.02.18.
// Copyright © 2018 User. All rights reserved.
//
import UIKit
protocol CameraControllerDelegate {
func didCapture(image: UIImage)
func didCancel()
}
class CameraController: UIViewController {
private let imageSize = 299 // New for XCode models, 227 for turicreate
// MARK: Outlets
@IBOutlet weak var imageButton: RoundedButton!
@IBOutlet weak var cropView: CropView!
@IBOutlet weak var cancelButton: RoundedButton!
@IBOutlet weak var cameraView: CameraView! {
didSet {
cameraView.configure()
}
}
var delegate: CameraControllerDelegate?
// MARK: Actions
@IBAction func backButtonPressed() {
delegate?.didCancel()
self.dismiss(animated: true)
}
@IBAction func imageButtonPressed() {
imageButton.isEnabled = false
event("Taking image")
cameraView.capture()
}
// MARK: Life cycle
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
cameraView.delegate = self
imageButton.imageView?.image = UIImage.templateImage(named: "camera")
setTintColor()
cameraView.launch { success, error in
guard let err = error else {
return
}
switch err {
case "No camera access": self.showNoCameraAccessAlert()
case "Camera error": self.showAlert("Unable to capture media")
default: self.showAlert("Error in camera setup")
}
}
self.imageButton.isEnabled = true
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
cameraView.complete()
}
private func setTintColor() {
let tint = AppDelegate.tintColor
cropView.lineColor = tint
imageButton.borderColor = tint
imageButton.imageView?.tintColor = tint
cancelButton.borderColor = tint
cancelButton.set(template: "cancel", with: tint)
}
// MARK: Alerts
private func showNoCameraAccessAlert() {
let alert = UIAlertController(title: "Unable to access the Camera",
message: "To enable access, go to Settings > Privacy > Camera and turn on Camera access for this app.",
preferredStyle: .alert,
blurStyle: .dark)
let okAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alert.addAction(okAction)
let settingsAction = UIAlertAction(title: "Settings", style: .default, handler: { _ in
// Take the user to Settings app to possibly change permission.
guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else { return }
if UIApplication.shared.canOpenURL(settingsUrl) {
UIApplication.shared.open(settingsUrl, completionHandler: nil)
}
})
alert.addAction(settingsAction)
self.present(alert, animated: true, completion: nil)
}
}
extension CameraController: PhotoCaptureHandlerDelegate {
func didCapture(_ image: UIImage?) {
event("Image captured")
let factor = CGFloat(cropView.relativeSize)
self.dismiss(animated: true)
let size = CGSize(width: imageSize, height: imageSize)
guard let img = image else {
self.error("No image captured")
return
}
guard delegate != nil else {
self.error("No delegate")
return
}
guard let masked = img.crop(factor: factor).circleMasked else {
self.error("Could not mask image")
return
}
// Only use 227 x 227 image
let scaled = masked.resize(to: size)
delegate!.didCapture(image: scaled)
}
}
extension CameraController: Logger {
static var logToken = "[Camera]"
}

View File

@ -0,0 +1,197 @@
//
// CameraView.swift
// CapFinder
//
// Created by User on 07.02.18.
// Copyright © 2018 User. All rights reserved.
//
import UIKit
import AVFoundation
class CameraView: UIView {
// MARK: UIView overrides
/**
Override for AVCapture
*/
override class var layerClass: AnyClass {
return AVCaptureVideoPreviewLayer.self
}
// MARK: Enums
private enum SessionSetupResult {
case success
case notAuthorized
case configurationFailed
}
// MARK: Variables
var delegate: PhotoCaptureHandlerDelegate? {
get {
return photoCaptureProcessor.delegate
}
set {
photoCaptureProcessor.delegate = newValue
}
}
private let session = AVCaptureSession()
private var isSessionRunning = false
/// Communicate with the session and other session objects on this queue.
private let sessionQueue = DispatchQueue(label: "session queue")
private var setupResult: SessionSetupResult = .success
var videoDeviceInput: AVCaptureDeviceInput!
private let photoOutput = AVCapturePhotoOutput()
private let photoCaptureProcessor = PhotoCaptureHandler()
var videoPreviewLayer: AVCaptureVideoPreviewLayer {
return layer as! AVCaptureVideoPreviewLayer
}
// MARK: Life cycle
func configure() {
videoPreviewLayer.session = session
checkPermission()
// Setup the capture session.
sessionQueue.async {
self.configureSession()
}
}
func launch(completionHandler: @escaping (Bool, String?) -> ()) {
sessionQueue.async {
switch self.setupResult {
case .success:
// Only setup observers and start the session running if setup succeeded.
self.session.startRunning()
self.isSessionRunning = self.session.isRunning
case .notAuthorized:
DispatchQueue.main.async {
completionHandler(false, "No camera access")
}
case .configurationFailed:
DispatchQueue.main.async {
completionHandler(false, "Camera error")
}
}
}
}
func complete() {
sessionQueue.async {
if self.setupResult == .success {
self.session.stopRunning()
self.isSessionRunning = self.session.isRunning
}
}
}
// MARK: Photo Capture
func capture() {
sessionQueue.async {
self.photoOutput.capturePhoto(
with: self.photoCaptureProcessor.photoSettings,
delegate: self.photoCaptureProcessor)
}
}
// MARK: Camera permissions
private func checkPermission() {
switch AVCaptureDevice.authorizationStatus(for: .video) {
case .authorized: break
case .notDetermined:
sessionQueue.suspend()
AVCaptureDevice.requestAccess(for: .video, completionHandler: { granted in
if !granted {
self.setupResult = .notAuthorized
}
self.sessionQueue.resume()
})
default:
// The user has previously denied access.
setupResult = .notAuthorized
}
}
// Call this on the session queue.
private func configureSession() {
if setupResult != .success {
return
}
session.beginConfiguration()
/*
We do not create an AVCaptureMovieFileOutput when setting up the session because the
AVCaptureMovieFileOutput does not support movie recording with AVCaptureSession.Preset.Photo.
*/
session.sessionPreset = .photo
// Add video input.
do {
guard let backCameraDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) else {
print("No camera on device")
setupResult = .configurationFailed
session.commitConfiguration()
return
}
let videoDeviceInput = try AVCaptureDeviceInput(device: backCameraDevice)
if session.canAddInput(videoDeviceInput) {
session.addInput(videoDeviceInput)
self.videoDeviceInput = videoDeviceInput
DispatchQueue.main.async {
self.videoPreviewLayer.connection?.videoOrientation = .portrait
}
} else {
print("Could not add video device input to the session")
setupResult = .configurationFailed
session.commitConfiguration()
return
}
} catch {
print("Could not create video device input: \(error)")
setupResult = .configurationFailed
session.commitConfiguration()
return
}
// Add photo output.
if session.canAddOutput(photoOutput) {
session.addOutput(photoOutput)
photoOutput.isHighResolutionCaptureEnabled = true
photoOutput.isDepthDataDeliveryEnabled = false
photoOutput.isDualCameraDualPhotoDeliveryEnabled = false
photoOutput.isLivePhotoCaptureEnabled = false
} else {
print("Could not add photo output to the session")
setupResult = .configurationFailed
session.commitConfiguration()
return
}
session.commitConfiguration()
}
}

View File

@ -0,0 +1,51 @@
/*
See LICENSE.txt for this samples licensing information.
Abstract:
Photo capture delegate.
*/
import AVFoundation
import Photos
protocol PhotoCaptureHandlerDelegate {
func didCapture(_ image: UIImage?)
}
class PhotoCaptureHandler: NSObject {
var delegate: PhotoCaptureHandlerDelegate?
var photoSettings: AVCapturePhotoSettings {
let photoSettings = AVCapturePhotoSettings()
photoSettings.flashMode = .off
return photoSettings
}
}
extension PhotoCaptureHandler: AVCapturePhotoCaptureDelegate {
/*
This extension includes all the delegate callbacks for AVCapturePhotoCaptureDelegate protocol
*/
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
guard error == nil else {
print("PhotoCaptureHandler: \(error!)")
delegate?.didCapture(nil)
return
}
guard let cgImage = photo.cgImageRepresentation()?.takeUnretainedValue() else {
print("PhotoCaptureHandler: No image captured")
delegate?.didCapture(nil)
return
}
let image = UIImage(cgImage: cgImage, scale: 1.0, orientation: .right)
DispatchQueue.main.async {
self.delegate?.didCapture(image)
}
}
}