commit 903414eedc28fa75ca0924e60c1946aacc85d699 Author: Andrew Walz Date: Sun Dec 25 16:59:29 2016 -1000 Initial commit for reupload diff --git a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj new file mode 100644 index 0000000..c34f98e --- /dev/null +++ b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.pbxproj @@ -0,0 +1,336 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1675A9761E00A68300B80903 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1675A9751E00A68300B80903 /* AppDelegate.swift */; }; + 1675A9781E00A68300B80903 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1675A9771E00A68300B80903 /* ViewController.swift */; }; + 1675A97B1E00A68300B80903 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1675A9791E00A68300B80903 /* Main.storyboard */; }; + 1675A97D1E00A68300B80903 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1675A97C1E00A68300B80903 /* Assets.xcassets */; }; + 1675A9801E00A68300B80903 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1675A97E1E00A68300B80903 /* LaunchScreen.storyboard */; }; + 1675A98D1E00A74A00B80903 /* PreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1675A9891E00A74A00B80903 /* PreviewView.swift */; }; + 1675A98E1E00A74A00B80903 /* SwiftyCamButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1675A98A1E00A74A00B80903 /* SwiftyCamButton.swift */; }; + 1675A98F1E00A74A00B80903 /* SwiftyCamViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1675A98B1E00A74A00B80903 /* SwiftyCamViewController.swift */; }; + 1675A9901E00A74A00B80903 /* SwiftyCamViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1675A98C1E00A74A00B80903 /* SwiftyCamViewControllerDelegate.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 1675A9721E00A68300B80903 /* DemoSwiftyCam.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DemoSwiftyCam.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 1675A9751E00A68300B80903 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 1675A9771E00A68300B80903 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 1675A97A1E00A68300B80903 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 1675A97C1E00A68300B80903 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 1675A97F1E00A68300B80903 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 1675A9811E00A68300B80903 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1675A9891E00A74A00B80903 /* PreviewView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PreviewView.swift; path = ../../Source/PreviewView.swift; sourceTree = ""; }; + 1675A98A1E00A74A00B80903 /* SwiftyCamButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftyCamButton.swift; path = ../../Source/SwiftyCamButton.swift; sourceTree = ""; }; + 1675A98B1E00A74A00B80903 /* SwiftyCamViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftyCamViewController.swift; path = ../../Source/SwiftyCamViewController.swift; sourceTree = ""; }; + 1675A98C1E00A74A00B80903 /* SwiftyCamViewControllerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftyCamViewControllerDelegate.swift; path = ../../Source/SwiftyCamViewControllerDelegate.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 1675A96F1E00A68300B80903 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1675A9691E00A68300B80903 = { + isa = PBXGroup; + children = ( + 1675A9741E00A68300B80903 /* DemoSwiftyCam */, + 1675A9731E00A68300B80903 /* Products */, + ); + sourceTree = ""; + }; + 1675A9731E00A68300B80903 /* Products */ = { + isa = PBXGroup; + children = ( + 1675A9721E00A68300B80903 /* DemoSwiftyCam.app */, + ); + name = Products; + sourceTree = ""; + }; + 1675A9741E00A68300B80903 /* DemoSwiftyCam */ = { + isa = PBXGroup; + children = ( + 1675A9911E00A74F00B80903 /* Source */, + 1675A9751E00A68300B80903 /* AppDelegate.swift */, + 1675A9771E00A68300B80903 /* ViewController.swift */, + 1675A9791E00A68300B80903 /* Main.storyboard */, + 1675A97C1E00A68300B80903 /* Assets.xcassets */, + 1675A97E1E00A68300B80903 /* LaunchScreen.storyboard */, + 1675A9811E00A68300B80903 /* Info.plist */, + ); + path = DemoSwiftyCam; + sourceTree = ""; + }; + 1675A9911E00A74F00B80903 /* Source */ = { + isa = PBXGroup; + children = ( + 1675A9891E00A74A00B80903 /* PreviewView.swift */, + 1675A98A1E00A74A00B80903 /* SwiftyCamButton.swift */, + 1675A98B1E00A74A00B80903 /* SwiftyCamViewController.swift */, + 1675A98C1E00A74A00B80903 /* SwiftyCamViewControllerDelegate.swift */, + ); + name = Source; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 1675A9711E00A68300B80903 /* DemoSwiftyCam */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1675A9841E00A68300B80903 /* Build configuration list for PBXNativeTarget "DemoSwiftyCam" */; + buildPhases = ( + 1675A96E1E00A68300B80903 /* Sources */, + 1675A96F1E00A68300B80903 /* Frameworks */, + 1675A9701E00A68300B80903 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DemoSwiftyCam; + productName = DemoSwiftyCam; + productReference = 1675A9721E00A68300B80903 /* DemoSwiftyCam.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 1675A96A1E00A68300B80903 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0810; + LastUpgradeCheck = 0820; + ORGANIZATIONNAME = Cappsule; + TargetAttributes = { + 1675A9711E00A68300B80903 = { + CreatedOnToolsVersion = 8.1; + DevelopmentTeam = LW28KCU8N5; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 1675A96D1E00A68300B80903 /* Build configuration list for PBXProject "DemoSwiftyCam" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 1675A9691E00A68300B80903; + productRefGroup = 1675A9731E00A68300B80903 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 1675A9711E00A68300B80903 /* DemoSwiftyCam */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 1675A9701E00A68300B80903 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1675A9801E00A68300B80903 /* LaunchScreen.storyboard in Resources */, + 1675A97D1E00A68300B80903 /* Assets.xcassets in Resources */, + 1675A97B1E00A68300B80903 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 1675A96E1E00A68300B80903 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1675A9781E00A68300B80903 /* ViewController.swift in Sources */, + 1675A9901E00A74A00B80903 /* SwiftyCamViewControllerDelegate.swift in Sources */, + 1675A9761E00A68300B80903 /* AppDelegate.swift in Sources */, + 1675A98F1E00A74A00B80903 /* SwiftyCamViewController.swift in Sources */, + 1675A98D1E00A74A00B80903 /* PreviewView.swift in Sources */, + 1675A98E1E00A74A00B80903 /* SwiftyCamButton.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 1675A9791E00A68300B80903 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 1675A97A1E00A68300B80903 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 1675A97E1E00A68300B80903 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 1675A97F1E00A68300B80903 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 1675A9821E00A68300B80903 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.1; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 1675A9831E00A68300B80903 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_SUSPICIOUS_MOVES = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.1; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 1675A9851E00A68300B80903 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LW28KCU8N5; + INFOPLIST_FILE = DemoSwiftyCam/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.Cappsule.DemoSwiftyCam; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + 1675A9861E00A68300B80903 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = LW28KCU8N5; + INFOPLIST_FILE = DemoSwiftyCam/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.Cappsule.DemoSwiftyCam; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1675A96D1E00A68300B80903 /* Build configuration list for PBXProject "DemoSwiftyCam" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1675A9821E00A68300B80903 /* Debug */, + 1675A9831E00A68300B80903 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1675A9841E00A68300B80903 /* Build configuration list for PBXNativeTarget "DemoSwiftyCam" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1675A9851E00A68300B80903 /* Debug */, + 1675A9861E00A68300B80903 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 1675A96A1E00A68300B80903 /* Project object */; +} diff --git a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..7cf9cd3 --- /dev/null +++ b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.xcworkspace/xcuserdata/DARKPR0.xcuserdatad/UserInterfaceState.xcuserstate b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.xcworkspace/xcuserdata/DARKPR0.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..26c4434 Binary files /dev/null and b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/project.xcworkspace/xcuserdata/DARKPR0.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/xcuserdata/DARKPR0.xcuserdatad/xcschemes/DemoSwiftyCam.xcscheme b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/xcuserdata/DARKPR0.xcuserdatad/xcschemes/DemoSwiftyCam.xcscheme new file mode 100644 index 0000000..9a743aa --- /dev/null +++ b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/xcuserdata/DARKPR0.xcuserdatad/xcschemes/DemoSwiftyCam.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/xcuserdata/DARKPR0.xcuserdatad/xcschemes/xcschememanagement.plist b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/xcuserdata/DARKPR0.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..7aa4b12 --- /dev/null +++ b/DemoSwiftyCam/DemoSwiftyCam.xcodeproj/xcuserdata/DARKPR0.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + DemoSwiftyCam.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 1675A9711E00A68300B80903 + + primary + + + + + diff --git a/DemoSwiftyCam/DemoSwiftyCam/AppDelegate.swift b/DemoSwiftyCam/DemoSwiftyCam/AppDelegate.swift new file mode 100644 index 0000000..dfee801 --- /dev/null +++ b/DemoSwiftyCam/DemoSwiftyCam/AppDelegate.swift @@ -0,0 +1,54 @@ +/*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 UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + func applicationWillResignActive(_ application: UIApplication) { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. + } + + func applicationDidEnterBackground(_ application: UIApplication) { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } + + func applicationWillEnterForeground(_ application: UIApplication) { + // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. + } + + func applicationDidBecomeActive(_ application: UIApplication) { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + } + + func applicationWillTerminate(_ application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } + + +} + diff --git a/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/AppIcon.appiconset/Contents.json b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..b8236c6 --- /dev/null +++ b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,48 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Camera.imageset/Camera@2x.png b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Camera.imageset/Camera@2x.png new file mode 100644 index 0000000..b98c6d8 Binary files /dev/null and b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Camera.imageset/Camera@2x.png differ diff --git a/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Camera.imageset/Camera@3x.png b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Camera.imageset/Camera@3x.png new file mode 100644 index 0000000..08466a4 Binary files /dev/null and b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Camera.imageset/Camera@3x.png differ diff --git a/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Camera.imageset/Contents.json b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Camera.imageset/Contents.json new file mode 100644 index 0000000..e9bc18f --- /dev/null +++ b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Camera.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "Camera@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "Camera@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Contents.json b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Flash.imageset/Contents.json b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Flash.imageset/Contents.json new file mode 100644 index 0000000..b602c3e --- /dev/null +++ b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Flash.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "flash@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "Flash@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Flash.imageset/Flash@3x.png b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Flash.imageset/Flash@3x.png new file mode 100644 index 0000000..f7f6b25 Binary files /dev/null and b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Flash.imageset/Flash@3x.png differ diff --git a/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Flash.imageset/flash@2x.png b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Flash.imageset/flash@2x.png new file mode 100644 index 0000000..3429e90 Binary files /dev/null and b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/Flash.imageset/flash@2x.png differ diff --git a/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/flipCamera.imageset/Contents.json b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/flipCamera.imageset/Contents.json new file mode 100644 index 0000000..6d041ed --- /dev/null +++ b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/flipCamera.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "flipcamera@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "flipCamera@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/flipCamera.imageset/flipCamera@3x.png b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/flipCamera.imageset/flipCamera@3x.png new file mode 100644 index 0000000..a3cfc93 Binary files /dev/null and b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/flipCamera.imageset/flipCamera@3x.png differ diff --git a/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/flipCamera.imageset/flipcamera@2x.png b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/flipCamera.imageset/flipcamera@2x.png new file mode 100644 index 0000000..06f2ae0 Binary files /dev/null and b/DemoSwiftyCam/DemoSwiftyCam/Assets.xcassets/flipCamera.imageset/flipcamera@2x.png differ diff --git a/DemoSwiftyCam/DemoSwiftyCam/Base.lproj/LaunchScreen.storyboard b/DemoSwiftyCam/DemoSwiftyCam/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..fdf3f97 --- /dev/null +++ b/DemoSwiftyCam/DemoSwiftyCam/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DemoSwiftyCam/DemoSwiftyCam/Base.lproj/Main.storyboard b/DemoSwiftyCam/DemoSwiftyCam/Base.lproj/Main.storyboard new file mode 100644 index 0000000..9648719 --- /dev/null +++ b/DemoSwiftyCam/DemoSwiftyCam/Base.lproj/Main.storyboard @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DemoSwiftyCam/DemoSwiftyCam/Info.plist b/DemoSwiftyCam/DemoSwiftyCam/Info.plist new file mode 100644 index 0000000..c2cc98e --- /dev/null +++ b/DemoSwiftyCam/DemoSwiftyCam/Info.plist @@ -0,0 +1,42 @@ + + + + + NSMicrophoneUsageDescription + To record audio with videos + NSCameraUsageDescription + To take photos and videos + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift b/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift new file mode 100644 index 0000000..d3f1dc7 --- /dev/null +++ b/DemoSwiftyCam/DemoSwiftyCam/ViewController.swift @@ -0,0 +1,83 @@ +/*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 UIKit + +class ViewController: SwiftyCamViewController, SwiftyCamViewControllerDelegate { + + @IBOutlet weak var flipCameraButton: UIButton! + @IBOutlet weak var toggleFlashButton: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + cameraDelegate = self + kMaximumVideoDuration = 10.0 + tapToFocus = true + pinchToZoom = true + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + let button : SwiftyCamButton = SwiftyCamButton(frame: CGRect(x: (self.view.frame.width / 2) - 35, y: self.view.frame.height - 85, width: 70, height: 70)) + button.delegate = self + button.setImage(UIImage(named: "Camera"), for: UIControlState()) + self.view.addSubview(button) + self.view.bringSubview(toFront: flipCameraButton) + self.view.bringSubview(toFront: toggleFlashButton) + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + func SwiftyCamDidTakePhoto(_ photo: UIImage) { + print(photo) + } + + func SwiftyCamDidBeginRecordingVideo() { + print("Did Begin Recording") + } + + func SwiftyCamDidFinishRecordingVideo() { + print("Did finish Recording") + } + + func SwiftyCamDidFinishProcessingVideoAt(_ url: String) { + print(url) + } + + func SwiftyCamDidFocusAtPoint(focusPoint: CGPoint) { + print(focusPoint) + } + + func SwiftyCamDidChangeZoomLevel(zoomLevel: CGFloat) { + print(zoomLevel) + } + + func SwiftyCamDidSwitchCameras(camera: SwiftyCamViewController.CameraSelection) { + print(camera) + } + + @IBAction func cameraSwitchAction(_ sender: Any) { + switchCamera() + } + + @IBAction func toggleFlashAction(_ sender: Any) { + toggleFlash() + } +} + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8ed1baa --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..4658a2d --- /dev/null +++ b/README.md @@ -0,0 +1,205 @@ +# SwiftyCam + + +[![Version](https://img.shields.io/cocoapods/v/SwiftyCam.svg?style=flat)](http://cocoapods.org/pods/SwiftyCam) +[![License](https://img.shields.io/cocoapods/l/SwiftyCam.svg?style=flat)](http://cocoapods.org/pods/SwiftyCam) +[![Platform](https://img.shields.io/cocoapods/p/SwiftyCam.svg?style=flat)](http://cocoapods.org/pods/SwiftyCam) + +## Overview + +SwiftyCam is a a simple, clean iOS Camera framework for easy photo and video capture. SwiftyCam allows users to capture both photos and videos from the same session with very little configuration. + +Configuring a Camera View Controller in AVFoundation can be tedious and time consuming. SwiftyCam is a drop in View Controller which gives complete control of the AVSession. + +## Requirements + +* iOS 8.0+ +* Swift 3.0+ + +## License + +SwiftyCam is available under the BSD license. See the LICENSE file for more info. + + +## Installation + +### Cocoapods: + +SwiftyCam is available through [CocoaPods](http://cocoapods.org). To install +it, simply add the following line to your Podfile: + +```ruby +pod "SwiftyCam" +``` + +### Manual Installation: + +Simply copy the contents of the Source folder into your project. + +## Usage + +Using SwiftyCam is very simple. + +### Prerequisites: + +As of iOS 10, Apple requires the additon of the NSCameraUsageDescription and NSMicrophoneUsageDescription strings to the info.plist of your application. Example: + + NSCameraUsageDescription + To Take Photos and Video + NSMicrophoneUsageDescription + To Record Audio With Video + +### Getting Started: + +Add the import statement to the View Controller you ware working in: + + import SwiftyCam + +SwiftyCam is a drop-in convenience framework. To create a Camera instance, create a new UIViewController subclass. Replace the UIViewController subclass declaration with SwiftyCamViewController: + + class MyCameraViewController : SwiftyCamViewController + +That is all that is required to setup the AVSession for photo and video capture. SwiftyCam will prompt the user for permission to use the camera/microphone, and configure both the device inputs and outputs. + +## Capture + +### SwiftyCamButton: + +SwiftyCam comes with a very convenient method of capturing media. SwiftyCamButton uses gesture recognizers to take either photos of videos. + +A single tap of the SwiftyCam button triggers a photo capture. + +A long press/tap and hold gesture initiates a video capture. Releasing the button ends the video recoring. + +To use a SwiftyCamButton, simply create one and assign the delegate to your SwiftyCamViewController: + + let captureButton = SwiftyCamButton(frame: buttonFrame) + captureButton.delegate = self + +### Manual: + +Capturing media with SwiftyCam is very simple. To capture a photo, simply call the takePhoto function: + + takePhoto() + +Capturing Video is just as easy. To begin recording video, call the startVideoRecording function: + + startVideoRecording() + +To end the capture of a video, call the endVideoRecordingFunction: + + endVideoRecording() + +###Delegate + +In order to acquire the photos and videos taken by either the SwiftyCamButton or manually, you must implement the SwiftyCamViewControllerDelegate and set the delegate to your view controller instance: + + class MyCameraViewController : SwiftyCamViewController, SwiftyCamViewControllerDelegate + +and in your viewDidLoad, assign the cameraDelegate to self: + + self.cameraDelegate = self + +####Delegate methods: + +**SwiftyCamDidTakePhoto(_ photo:UIImage)** - Return a UIImage captured from the AVSession + +**SwiftyCamDidBeginRecordingVideo()** - Called when the capture session begins recording a video + +**SwiftyCamDidFinishRecordingVideo()** - Called when the capture session has finished recording a video and has begun processing + +**SwiftyCamDidFinishProcessingVideoAt(_ url: String)** - Called when the capture session finished processing the video returns the location on disk the video is stored. This will always be in the temorary folder of the device. + +**SwiftyCamDidSwitchCameras(camera: SwiftyCamViewController.CameraSelection)** - Called when the user has initiated a switch in camera orientations. + +**SwiftyCamDidFocusAtPoint(focusPoint: CGPoint)** - Returns the point on the preview where a tap to focus was initiated (Will only be called if *tapToFocus* is set to *true*) + +**SwiftyCamDidChangeZoomLevel(zoomLevel: CGFloat)** - Returns the current zoom level of the preview layer after a pinch to zoom has been initiated. Will be called several times (Will only be called if *pinchToZoom* is set to *true*) + +**SwiftyCamDidFailCameraPermissionSettings()** - Called during SwiftyCamViewController launch if the user has denied permission to access either the camera of microphone (Will only be called if *promptToAppPrivacySettings* is set to *false*) + +## Flash + +The flash(torch) can be enabled on the device by calling: + + toggleFlash() + +The flash will only be enabled if the current camera is the rear camera and will automatically if the camera switches or the View Controller is dismissed. + +## Switching Camera + +SwiftyCam supports capture from both the front and back cameras. To switch cameras, call the function: + + switchCamera() + +Tap-to-focus, pinch-to-zoom and camera flash are not supported when the front facing camera is selected. *Switching video while video is being recorded is not currently supported* + +##Configuration + +SwiftyCam has several options for configurating the functionality of the capture: + +### Video Quality + +Video quality can be set by the **videoQuality** property of SwiftyCamViewController. The choices available correspond to the matching **AVCaptureSessionPreset**: + +* **.high** (AVCapturePresetHigh) +* **.medium** (AVCapturePresetMedium) +* **.low** (AVCapturePresetLow) +* **.resolution352x288** (AVCaptureSessionPreset352x288) +* **.resolution640x480** (AVCaptureSessionPreset640x480) +* **.resolution1280x720** (AVCaptureSessionPreset1280x720) +* **.resolution1920x1080** (AVCaptureSessionPreset1920x1080) +* **.resolution3840x2160** (AVCaptureSessionPreset3840x2160) +* **.iframe960x540** (AVCaptureSessionPresetiFrame960x540) +* **.iframe1280x720** (AVCaptureSessionPresetiFrame1280x720) + +The default value is **.resolution1920x1080** + +### Maximum Video Duration + +If using a SwiftyCamButton, you can set a maximum video duration for the length of video. The video recording will me automatically stopped once the time limit has been reached and the delegate method **SwiftyCamDidFinishRecordingVideo** will be called. To set this value, simply change the **kMaximumVideoDuration** value: + + kMaximumVideoDuration = 10.0 + +A value of **0.0** will allow for unlimited video recording via the SwiftyCamButton. The default value is **0.0**. + +## Camera Zoom + +SwiftyCam supports digital zoom of the camera session via pinch gestures. The gestures work similar to the default iOS app and will zoom to the maximum supported zoom level. Camera zoom is only supported on the rear facing camera. AVFoundation does not currently support front facing camera zoom. To disable this feature, change the **pinchToZoom** property: + + pinchToZoom = false + +By default, **pinchToZoom** is enabled. + +## Camera Focus + +SwiftyCam, by default, support tap to focus on the video preview. SwiftyCam will set the focus and exposure levels of the session to the tapped point. Autofocus and autoexposure will be resumed once SwiftyCam detects significant movement from the tapped point. To disable this feature, change the **tapToFocus** property: + + tapToFocus = false + +By default, **tapToFocus** is enabled. If you wish to show a on screen animation when a tap to focus is initiated, you can use the **SwiftyCamDidFocusAtPoint(focusPoint:)** to get the coordinates of tap and provide your own tap animation + +## Privacy + +When a user firsts launch SwiftyCamViewController, they will be prompted for permission for access to the cameras and microphones. By default, if a user declines access to the hardware, SwiftyCam will provide a prompt to the App privacy settings inside the iOS settings application. If you wish to change this behaviour, the **promptToAppPrivacySettings** property can be modified: + + promptToAppPrivacySettings = false + +Instead of prompting the user to the settings application, the delegate method **SwiftyCamDidFailCameraPermissionSettings** will be called and will have to be manually handled. + +## Miscellaneous + +Other properties: + +* **isCameraFlashOn** - Bool +* **isVideoRecording** - Bool +* **isSessionRunning** - Bool +* **currentCamera** - CameraSelection + + +### Contact + +If you have any questions, requests, or enhancements, feel free to submit a pull request, create an issue, or contact me in person: + +**Andrew Walz** +**andrewjwalz@gmail.com** diff --git a/Source/PreviewView.swift b/Source/PreviewView.swift new file mode 100644 index 0000000..7d4c52d --- /dev/null +++ b/Source/PreviewView.swift @@ -0,0 +1,49 @@ +/*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 UIKit +import AVFoundation + +class PreviewView: UIView { + + override init(frame: CGRect) { + super.init(frame: frame) + self.backgroundColor = UIColor.black + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + var videoPreviewLayer: AVCaptureVideoPreviewLayer { + return layer as! AVCaptureVideoPreviewLayer + } + + var session: AVCaptureSession? { + get { + return videoPreviewLayer.session + } + set { + videoPreviewLayer.session = newValue + } + } + + // MARK: UIView + + override class var layerClass : AnyClass { + return AVCaptureVideoPreviewLayer.self + } +} diff --git a/Source/SwiftyCamButton.swift b/Source/SwiftyCamButton.swift new file mode 100644 index 0000000..b8bf121 --- /dev/null +++ b/Source/SwiftyCamButton.swift @@ -0,0 +1,82 @@ +/*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 UIKit + +public protocol SwiftyCamButtonDelegate { + func buttonWasTapped() + func buttonDidBeginLongPress() + func buttonDidEndLongPress() + func longPressDidReachMaximumDuration() + func setMaxiumVideoDuration() -> Double +} + + +open class SwiftyCamButton: UIButton { + + public var delegate: SwiftyCamButtonDelegate? + + fileprivate var timer : Timer? + + override public init(frame: CGRect) { + super.init(frame: frame) + createGestureRecognizers() + } + + required public init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + createGestureRecognizers() + } + + @objc fileprivate func Tap() { + self.delegate?.buttonWasTapped() + } + + @objc fileprivate func LongPress(_ sender:UILongPressGestureRecognizer!) { + if (sender.state == UIGestureRecognizerState.ended) { + invalidateTimer() + self.delegate?.buttonDidEndLongPress() + } else if (sender.state == UIGestureRecognizerState.began) { + self.delegate?.buttonDidBeginLongPress() + startTimer() + } + } + + @objc fileprivate func timerFinished() { + invalidateTimer() + self.delegate?.longPressDidReachMaximumDuration() + } + + fileprivate func startTimer() { + if let duration = delegate?.setMaxiumVideoDuration() { + if duration != 0.0 && duration > 0.0 { + timer = Timer.scheduledTimer(timeInterval: duration, target: self, selector: #selector(SwiftyCamButton.timerFinished), userInfo: nil, repeats: false) + } + } + } + + fileprivate func invalidateTimer() { + timer?.invalidate() + timer = nil + } + + fileprivate func createGestureRecognizers() { + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(SwiftyCamButton.Tap)) + let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(SwiftyCamButton.LongPress)) + self.addGestureRecognizer(tapGesture) + self.addGestureRecognizer(longGesture) + } +} diff --git a/Source/SwiftyCamViewController.swift b/Source/SwiftyCamViewController.swift new file mode 100644 index 0000000..93ad9d9 --- /dev/null +++ b/Source/SwiftyCamViewController.swift @@ -0,0 +1,536 @@ +/*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 UIKit +import AVFoundation + +open class SwiftyCamViewController: UIViewController { + + public enum CameraSelection { + case rear + case front + } + + public enum VideoQuality { + case high + case medium + case low + case resolution352x288 + case resolution640x480 + case resolution1280x720 + case resolution1920x1080 + case resolution3840x2160 + case iframe960x540 + case iframe1280x720 + } + + fileprivate enum SessionSetupResult { + case success + case notAuthorized + case configurationFailed + } + + public var cameraDelegate: SwiftyCamViewControllerDelegate? + + public var kMaximumVideoDuration : Double = 0.0 + public var videoQuality : VideoQuality = .resolution1920x1080 + public var pinchToZoom = true + public var tapToFocus = true + public var promptToAppPrivacySettings = true + private(set) public var isCameraFlashOn = false + private(set) public var isVideRecording = false + private(set) public var isSessionRunning = false + private(set) public var currentCamera = CameraSelection.rear + fileprivate let session = AVCaptureSession() + fileprivate let sessionQueue = DispatchQueue(label: "session queue", attributes: []) + fileprivate var zoomScale = CGFloat(1.0) + fileprivate var beginZoomScale = CGFloat(1.0) + fileprivate var setupResult = SessionSetupResult.success + fileprivate var backgroundRecordingID : UIBackgroundTaskIdentifier? = nil + fileprivate var videoDeviceInput : AVCaptureDeviceInput! + fileprivate var movieFileOutput : AVCaptureMovieFileOutput? + fileprivate var photoFileOutput : AVCaptureStillImageOutput? + fileprivate var videoDevice : AVCaptureDevice? + fileprivate var previewLayer : PreviewView! + + + + override open func viewDidLoad() { + super.viewDidLoad() + previewLayer = PreviewView(frame: self.view.frame) + addGestureRecognizers(toView: previewLayer) + self.view.addSubview(previewLayer) + previewLayer.session = session + + switch AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo){ + case .authorized: + break + case .notDetermined: + sessionQueue.suspend() + AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo, completionHandler: { [unowned self] granted in + if !granted { + self.setupResult = .notAuthorized + } + self.sessionQueue.resume() + }) + default: + setupResult = .notAuthorized + } + sessionQueue.async { [unowned self] in + self.configureSession() + } + } + + override open func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + sessionQueue.async { + switch self.setupResult { + case .success: + self.session.startRunning() + self.isSessionRunning = self.session.isRunning + case .notAuthorized: + self.promptToAppSettings() + case .configurationFailed: + DispatchQueue.main.async(execute: { [unowned self] in + let message = NSLocalizedString("Unable to capture media", comment: "Alert message when something goes wrong during capture session configuration") + let alertController = UIAlertController(title: "AVCam", message: message, preferredStyle: .alert) + alertController.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "Alert OK button"), style: .cancel, handler: nil)) + + self.present(alertController, animated: true, completion: nil) + }) + } + } + } + + override open func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + if self.isSessionRunning == true { + self.session.stopRunning() + self.isSessionRunning = false + } + disableFlash() + } + + func takePhoto() { + if let videoConnection = photoFileOutput?.connection(withMediaType: AVMediaTypeVideo) { + videoConnection.videoOrientation = AVCaptureVideoOrientation.portrait + photoFileOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: {(sampleBuffer, error) in + if (sampleBuffer != nil) { + let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer) + let image = self.processPhoto(imageData!) + self.cameraDelegate?.SwiftyCamDidTakePhoto(image) + } + }) + } + } + + func startVideoRecording() { + guard let movieFileOutput = self.movieFileOutput else { + return + } + + let videoPreviewLayerOrientation = previewLayer!.videoPreviewLayer.connection.videoOrientation + + sessionQueue.async { [unowned self] in + if !movieFileOutput.isRecording { + if UIDevice.current.isMultitaskingSupported { + self.backgroundRecordingID = UIApplication.shared.beginBackgroundTask(expirationHandler: nil) + } + + // Update the orientation on the movie file output video connection before starting recording. + let movieFileOutputConnection = self.movieFileOutput?.connection(withMediaType: AVMediaTypeVideo) + + + //flip video output if front facing camera is selected + if self.currentCamera == .front { + movieFileOutputConnection?.isVideoMirrored = true + } + movieFileOutputConnection?.videoOrientation = videoPreviewLayerOrientation + + // Start recording to a temporary file. + let outputFileName = UUID().uuidString + let outputFilePath = (NSTemporaryDirectory() as NSString).appendingPathComponent((outputFileName as NSString).appendingPathExtension("mov")!) + movieFileOutput.startRecording(toOutputFileURL: URL(fileURLWithPath: outputFilePath), recordingDelegate: self) + self.isVideRecording = true + self.cameraDelegate?.SwiftyCamDidBeginRecordingVideo() + } + else { + movieFileOutput.stopRecording() + } + } + } + + func endVideoRecording() { + if self.movieFileOutput?.isRecording == true { + self.isVideRecording = false + movieFileOutput!.stopRecording() + self.cameraDelegate?.SwiftyCamDidFinishRecordingVideo() + } + } + + func switchCamera() { + if isVideRecording == true { + print("[SwiftyCam]: Switching between cameras while recoring video is not supported") + return + } + switch currentCamera { + case .front: + self.currentCamera = .rear + case .rear: + self.currentCamera = .front + } + + sessionQueue.async { [unowned self] in + let currentInputs : [AVCaptureInput] = self.session.inputs as! [AVCaptureInput] + let currentOutputs : [AVCaptureOutput] = self.session.outputs as! [AVCaptureOutput] + + for input in currentInputs { + self.session.removeInput(input) + } + for output in currentOutputs { + self.session.removeOutput(output) + } + + self.configureSession() + self.cameraDelegate?.SwiftyCamDidSwitchCameras(camera: self.currentCamera) + } + disableFlash() + } + + func toggleFlash() { + guard self.currentCamera == .rear else { + return + } + let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo) + if (device?.hasTorch)! { + do { + try device?.lockForConfiguration() + if (device?.torchMode == AVCaptureTorchMode.on) { + device?.torchMode = AVCaptureTorchMode.off + self.isCameraFlashOn = false + } else { + do { + try device?.setTorchModeOnWithLevel(1.0) + self.isCameraFlashOn = true + } catch { + print("[SwiftyCam]: \(error)") + } + } + device?.unlockForConfiguration() + } catch { + print("[SwiftyCam]: \(error)") + } + } + } + + override open func touchesBegan(_ touches: Set, with event: UIEvent?) { + guard tapToFocus == true, currentCamera == .rear else { + return + } + let screenSize = previewLayer!.bounds.size + if let touchPoint = touches.first { + let x = touchPoint.location(in: previewLayer!).y / screenSize.height + let y = 1.0 - touchPoint.location(in: previewLayer!).x / screenSize.width + let focusPoint = CGPoint(x: x, y: y) + + if let device = videoDevice { + do { + try device.lockForConfiguration() + + device.focusPointOfInterest = focusPoint + //device.focusMode = .continuousAutoFocus + device.focusMode = .autoFocus + //device.focusMode = .locked + device.exposurePointOfInterest = focusPoint + device.exposureMode = AVCaptureExposureMode.continuousAutoExposure + device.unlockForConfiguration() + self.cameraDelegate?.SwiftyCamDidFocusAtPoint(focusPoint: touchPoint.location(in: previewLayer)) + } + catch { + // just ignore + } + } + } + } + + /**************************************** Private Functions ****************************************/ + + fileprivate func configureSession() { + guard setupResult == .success else { + return + } + session.beginConfiguration() + + addVideoInput() + addAudioInput() + configureVideoOutput() + configurePhotoOutput() + + session.commitConfiguration() + } + + fileprivate func addVideoInput() { + switch currentCamera { + case .front: + videoDevice = SwiftyCamViewController.deviceWithMediaType(AVMediaTypeVideo, preferringPosition: .front) + case .rear: + videoDevice = SwiftyCamViewController.deviceWithMediaType(AVMediaTypeVideo, preferringPosition: .back) + } + + if let device = videoDevice { + do { + try device.lockForConfiguration() + if device.isFocusModeSupported(.continuousAutoFocus) { + device.focusMode = .continuousAutoFocus + if device.isSmoothAutoFocusSupported { + device.isSmoothAutoFocusEnabled = true + } + } + + if device.isExposureModeSupported(.continuousAutoExposure) { + device.exposureMode = .continuousAutoExposure + } + + if device.isWhiteBalanceModeSupported(.continuousAutoWhiteBalance) { + device.whiteBalanceMode = .continuousAutoWhiteBalance + } + + device.unlockForConfiguration() + } catch { + print("[SwiftyCam]: Error locking configuration") + } + } + + do { + let videoDeviceInput = try AVCaptureDeviceInput(device: videoDevice) + + if session.canAddInput(videoDeviceInput) { + session.addInput(videoDeviceInput) + self.videoDeviceInput = videoDeviceInput + } else { + print("[SwiftyCam]: Could not add video device input to the session") + setupResult = .configurationFailed + session.commitConfiguration() + return + } + } catch { + print("[SwiftyCam]: Could not create video device input: \(error)") + setupResult = .configurationFailed + return + } + } + + fileprivate func addAudioInput() { + do { + let audioDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio) + let audioDeviceInput = try AVCaptureDeviceInput(device: audioDevice) + + if session.canAddInput(audioDeviceInput) { + session.addInput(audioDeviceInput) + } + else { + print("[SwiftyCam]: Could not add audio device input to the session") + } + } + catch { + print("[SwiftyCam]: Could not create audio device input: \(error)") + } + } + + fileprivate func configureVideoOutput() { + let movieFileOutput = AVCaptureMovieFileOutput() + + if self.session.canAddOutput(movieFileOutput) { + self.session.addOutput(movieFileOutput) + self.session.sessionPreset = videoInputPresetFromVideoQuality(quality: videoQuality) + print(videoInputPresetFromVideoQuality(quality: videoQuality)) + if let connection = movieFileOutput.connection(withMediaType: AVMediaTypeVideo) { + if connection.isVideoStabilizationSupported { + connection.preferredVideoStabilizationMode = .auto + } + } + self.movieFileOutput = movieFileOutput + } + } + + fileprivate func configurePhotoOutput() { + let photoFileOutput = AVCaptureStillImageOutput() + + if self.session.canAddOutput(photoFileOutput) { + photoFileOutput.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG] + self.session.addOutput(photoFileOutput) + self.photoFileOutput = photoFileOutput + } + } + + fileprivate func processPhoto(_ imageData: Data) -> UIImage { + let dataProvider = CGDataProvider(data: imageData as CFData) + let cgImageRef = CGImage(jpegDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: CGColorRenderingIntent.defaultIntent) + + var image: UIImage! + + switch self.currentCamera { + case .front: + image = UIImage(cgImage: cgImageRef!, scale: 1.0, orientation: .rightMirrored) + case .rear: + image = UIImage(cgImage: cgImageRef!, scale: 1.0, orientation: .right) + } + return image + } + + @objc fileprivate func zoomGesture(pinch: UIPinchGestureRecognizer) { + guard pinchToZoom == true else { + return + } + do { + let captureDevice = AVCaptureDevice.devices().first as? AVCaptureDevice + try captureDevice?.lockForConfiguration() + + zoomScale = max(1.0, min(beginZoomScale * pinch.scale, captureDevice!.activeFormat.videoMaxZoomFactor)) + + captureDevice?.videoZoomFactor = zoomScale + + self.cameraDelegate?.SwiftyCamDidChangeZoomLevel(zoomLevel: zoomScale) + + captureDevice?.unlockForConfiguration() + + } catch { + print("[SwiftyCam]: Error locking configuration") + } + } + + fileprivate func addGestureRecognizers(toView: UIView) { + let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(zoomGesture(pinch:))) + pinchGesture.delegate = self + toView.addGestureRecognizer(pinchGesture) + } + + fileprivate func promptToAppSettings() { + guard promptToAppPrivacySettings == true else { + self.cameraDelegate?.SwiftyCamDidFailCameraPermissionSettings() + return + } + DispatchQueue.main.async(execute: { [unowned self] in + let message = NSLocalizedString("AVCam doesn't have permission to use the camera, please change privacy settings", comment: "Alert message when the user has denied access to the camera") + let alertController = UIAlertController(title: "AVCam", message: message, preferredStyle: .alert) + alertController.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "Alert OK button"), style: .cancel, handler: nil)) + alertController.addAction(UIAlertAction(title: NSLocalizedString("Settings", comment: "Alert button to open Settings"), style: .default, handler: { action in + if #available(iOS 10.0, *) { + UIApplication.shared.openURL(URL(string: UIApplicationOpenSettingsURLString)!) + } else { + if let appSettings = URL(string: UIApplicationOpenSettingsURLString) { + UIApplication.shared.openURL(appSettings) + } + } + })) + self.present(alertController, animated: true, completion: nil) + }) + } + + fileprivate func videoInputPresetFromVideoQuality(quality: VideoQuality) -> String { + switch quality { + case .high: return AVCaptureSessionPresetHigh + case .medium: return AVCaptureSessionPresetMedium + case .low: return AVCaptureSessionPresetLow + case .resolution352x288: return AVCaptureSessionPreset352x288 + case .resolution640x480: return AVCaptureSessionPreset640x480 + case .resolution1280x720: return AVCaptureSessionPreset1280x720 + case .resolution1920x1080: return AVCaptureSessionPreset1920x1080 + case .iframe960x540: return AVCaptureSessionPresetiFrame960x540 + case .iframe1280x720: return AVCaptureSessionPresetiFrame1280x720 + case .resolution3840x2160: + if #available(iOS 9.0, *) { + return AVCaptureSessionPreset3840x2160 + } + else { + print("[SwiftyCam]: Resolution 3840x2160 not supported") + return AVCaptureSessionPresetPhoto + } + } + } + + fileprivate class func deviceWithMediaType(_ mediaType: String, preferringPosition position: AVCaptureDevicePosition) -> AVCaptureDevice? { + if let devices = AVCaptureDevice.devices(withMediaType: mediaType) as? [AVCaptureDevice] { + return devices.filter({ $0.position == position }).first + } + return nil + } + + fileprivate func enableFlash() { + if self.isCameraFlashOn == false { + toggleFlash() + } + } + + fileprivate func disableFlash() { + if self.isCameraFlashOn == true { + toggleFlash() + } + } +} + +extension SwiftyCamViewController : SwiftyCamButtonDelegate { + + public func setMaxiumVideoDuration() -> Double { + return kMaximumVideoDuration + } + + public func buttonWasTapped() { + takePhoto() + } + + public func buttonDidBeginLongPress() { + startVideoRecording() + } + + public func buttonDidEndLongPress() { + endVideoRecording() + } + + public func longPressDidReachMaximumDuration() { + endVideoRecording() + } +} + +extension SwiftyCamViewController : AVCaptureFileOutputRecordingDelegate { + public func capture(_ captureOutput: AVCaptureFileOutput!, didFinishRecordingToOutputFileAt outputFileURL: URL!, fromConnections connections: [Any]!, error: Error!) { + if let currentBackgroundRecordingID = backgroundRecordingID { + backgroundRecordingID = UIBackgroundTaskInvalid + + if currentBackgroundRecordingID != UIBackgroundTaskInvalid { + UIApplication.shared.endBackgroundTask(currentBackgroundRecordingID) + } + } + if error != nil { + print("[SwiftyCam]: Movie file finishing error: \(error)") + } else { + self.cameraDelegate?.SwiftyCamDidFinishProcessingVideoAt(outputFileURL.path) + } + } +} + +extension SwiftyCamViewController : UIGestureRecognizerDelegate { + public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + if gestureRecognizer.isKind(of: UIPinchGestureRecognizer.self) { + beginZoomScale = zoomScale; + } + return true + } +} + + + + diff --git a/Source/SwiftyCamViewControllerDelegate.swift b/Source/SwiftyCamViewControllerDelegate.swift new file mode 100644 index 0000000..525f89b --- /dev/null +++ b/Source/SwiftyCamViewControllerDelegate.swift @@ -0,0 +1,65 @@ +/*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 UIKit + +public protocol SwiftyCamViewControllerDelegate { + func SwiftyCamDidTakePhoto(_ photo:UIImage) + func SwiftyCamDidBeginRecordingVideo() + func SwiftyCamDidFinishRecordingVideo() + func SwiftyCamDidFinishProcessingVideoAt(_ url: String) + func SwiftyCamDidSwitchCameras(camera: SwiftyCamViewController.CameraSelection) + func SwiftyCamDidFocusAtPoint(focusPoint: CGPoint) + func SwiftyCamDidChangeZoomLevel(zoomLevel: CGFloat) + func SwiftyCamDidFailCameraPermissionSettings() +} + +public extension SwiftyCamViewControllerDelegate { + func SwiftyCamDidTakePhoto(_ photo:UIImage) { + // Optional + } + + func SwiftyCamDidBeginRecordingVideo() { + // Optional + } + + func SwiftyCamDidFinishRecordingVideo() { + // Optional + } + + func SwiftyCamDidFinishProcessingVideoAt(_ url: String) { + // Optional + } + + func SwiftyCamDidSwitchCameras(camera: SwiftyCamViewController.CameraSelection) { + // Optional + } + + func SwiftyCamDidFocusAtPoint(focusPoint: CGPoint) { + // Optional + } + + func SwiftyCamDidChangeZoomLevel(zoomLevel: CGFloat) { + // Optional + } + + func SwiftyCamDidFailCameraPermissionSettings() { + // Optional + } +} + + + diff --git a/SwiftyCam.podspec b/SwiftyCam.podspec new file mode 100644 index 0000000..25515e1 --- /dev/null +++ b/SwiftyCam.podspec @@ -0,0 +1,44 @@ +# +# Be sure to run `pod lib lint SwiftyCam.podspec' to ensure this is a +# valid spec before submitting. +# +# Any lines starting with a # are optional, but their use is encouraged +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# + +Pod::Spec.new do |s| + s.name = 'SwiftyCam' + s.version = '1.0.0' + s.summary = 'A Simple, Snapchat-style camera Framework written in Swift' + s.ios.deployment_target = '8.0' + + +# This description is used to generate tags and improve search results. +# * Think: What does it do? Why did you write it? What is the focus? +# * Try to keep it short, snappy and to the point. +# * Write the description between the DESC delimiters below. +# * Finally, don't worry about the indent, CocoaPods strips it! + +s.description = <<-DESC +A drop in Camera View Controller for capturing photos and videos from one AVSession. Written in Swift. + DESC + + s.homepage = 'https://github.com/Awalz/SwiftyCam' + # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' + s.license = { :type => 'BSD', :file => 'LICENSE' } + s.author = { 'Andrew Walz' => 'andrewjwalz@gmail.com' } + s.source = { :git => 'https://github.com/Awalz/SwiftyCam.git', :tag => s.version.to_s } + # s.social_media_url = 'https://twitter.com/' + + s.ios.deployment_target = '8.0' + + s.source_files = 'Source/**/*' + + # s.resource_bundles = { + # 'SwiftyCam' => ['SwiftyCam/Assets/*.png'] + # } + + # s.public_header_files = 'Pod/Classes/**/*.h' + # s.frameworks = 'UIKit', 'MapKit' + # s.dependency 'AFNetworking', '~> 2.3' +end