├── LICENSE ├── PrismaSimpleImagePicker.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── roylee.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── roylee.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── PrismaSimpleImagePicker.xcscheme │ └── xcschememanagement.plist ├── PrismaSimpleImagePicker ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── AppIcon29x29@2x.png │ │ ├── AppIcon29x29@3x.png │ │ ├── AppIcon40x40@2x.png │ │ ├── AppIcon40x40@3x.png │ │ ├── AppIcon60x60@2x.png │ │ ├── AppIcon60x60@3x.png │ │ └── Contents.json │ ├── Contents.json │ ├── Oval.imageset │ │ ├── Contents.json │ │ ├── Oval@2x.png │ │ └── Oval@3x.png │ ├── StyleSelected.imageset │ │ ├── Contents.json │ │ ├── StyleSelected.png │ │ ├── StyleSelected@2x.png │ │ └── StyleSelected@3x.png │ ├── albums-arrow.imageset │ │ ├── Contents.json │ │ ├── albums-arrow@2x.png │ │ └── albums-arrow@3x.png │ ├── arrows.imageset │ │ ├── Contents.json │ │ ├── arrows@2x.png │ │ └── arrows@3x.png │ ├── back.imageset │ │ ├── Contents.json │ │ ├── back@2x.png │ │ └── back@3x.png │ ├── cross.imageset │ │ ├── Contents.json │ │ ├── cross@2x.png │ │ └── cross@3x.png │ ├── facebook-small.imageset │ │ ├── Contents.json │ │ └── facebook-small@2x.png │ ├── facebook.imageset │ │ ├── Contents.json │ │ ├── facebook@2x.png │ │ └── facebook@3x.png │ ├── flash-auto.imageset │ │ ├── Contents.json │ │ ├── flash-auto@2x.png │ │ └── flash-auto@3x.png │ ├── flash-on.imageset │ │ ├── Contents.json │ │ ├── flash-on@2x.png │ │ └── flash-on@3x.png │ ├── flash.imageset │ │ ├── Contents.json │ │ ├── flash@2x.png │ │ └── flash@3x.png │ ├── flip.imageset │ │ ├── Contents.json │ │ ├── flip@2x.png │ │ └── flip@3x.png │ ├── instagram-small.imageset │ │ ├── Contents.json │ │ └── instagram-small@2x.png │ ├── instagram.imageset │ │ ├── Contents.json │ │ ├── instagram@2x.png │ │ └── instagram@3x.png │ ├── nocamera.imageset │ │ ├── Contents.json │ │ ├── nocamera@2x.png │ │ └── nocamera@3x.png │ ├── ok.imageset │ │ ├── Contents.json │ │ ├── ok@2x.png │ │ └── ok@3x.png │ ├── photos.imageset │ │ ├── Contents.json │ │ ├── photos@2x.png │ │ └── photos@3x.png │ ├── rotate-left.imageset │ │ ├── Contents.json │ │ ├── rotate-left@2x.png │ │ └── rotate-left@3x.png │ ├── rotate-right.imageset │ │ ├── Contents.json │ │ ├── rotate-right@2x.png │ │ └── rotate-right@3x.png │ ├── save-small.imageset │ │ ├── Contents.json │ │ └── save-small@2x.png │ ├── save.imageset │ │ ├── Contents.json │ │ ├── save@2x.png │ │ └── save@3x.png │ ├── settings.imageset │ │ ├── Contents.json │ │ ├── settings@2x.png │ │ └── settings@3x.png │ ├── share-small.imageset │ │ ├── Contents.json │ │ └── share-small@2x.png │ ├── share.imageset │ │ ├── Contents.json │ │ ├── share@2x.png │ │ └── share@3x.png │ ├── vk-small.imageset │ │ ├── Contents.json │ │ └── vk-small@2x.png │ ├── vk.imageset │ │ ├── Contents.json │ │ ├── vk@2x.png │ │ └── vk@3x.png │ ├── watermark.imageset │ │ ├── Contents.json │ │ └── watermark@2x.png │ ├── weibo-small.imageset │ │ ├── Contents.json │ │ └── weibo-small@2x.png │ ├── weibo.imageset │ │ ├── Contents.json │ │ ├── weibo@2x.png │ │ └── weibo@3x.png │ ├── weсhat-small.imageset │ │ ├── Contents.json │ │ └── weсhat-small@2x.png │ └── weсhat.imageset │ │ ├── Contents.json │ │ ├── weсhat@2x.png │ │ └── weсhat@3x.png ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── PrismaImagePicker │ ├── PickerController │ │ ├── PMImageGroupController.swift │ │ ├── PMImageGroupController.xib │ │ ├── PMImagePickerController.swift │ │ ├── PMImageViewController.swift │ │ └── PMImageViewController.xib │ ├── PickerHelper │ │ ├── PMDeviceOrientation.swift │ │ └── PMImageManger.swift │ ├── PickerModel │ │ └── PMGroupModel.swift │ └── PickerView │ │ ├── PMImageGroupCell.swift │ │ ├── PMImageGroupCell.xib │ │ ├── PMPhotoGridView.swift │ │ ├── PMPhotoHeaderItem.swift │ │ ├── PMPhotoHeaderView.swift │ │ └── PMPickerTitleButton.swift ├── PrismaPhotoCapture │ ├── PMImageEditController.swift │ ├── PMImageProcessController.swift │ ├── PMImageProtocol.swift │ ├── PMImageSettingController.swift │ ├── PMImageSettingController.xib │ ├── PMNavigationController.swift │ ├── PMRootViewController.swift │ └── PNImageCaptureController.swift ├── PrismaViews │ ├── PMCaptureButtom.swift │ ├── PMStyleCell.swift │ └── PMStyleHeaderView.swift ├── PrismaWebImage │ ├── PMImageCache.swift │ ├── PMImageDownloader.swift │ └── PMImageSession.swift ├── ViewController.swift └── styles.json ├── PrismaSimpleImagePickerTests ├── Info.plist └── PrismaSimpleImagePickerTests.swift ├── README.md └── ScreenShots ├── cropimage.png ├── frameworks.png ├── logo.png ├── possion.png ├── prismanib.png ├── screenshot1.gif ├── screenshot2.gif └── screenshot3.gif /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Roy lee. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker.xcodeproj/project.xcworkspace/xcuserdata/roylee.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker.xcodeproj/project.xcworkspace/xcuserdata/roylee.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /PrismaSimpleImagePicker.xcodeproj/xcuserdata/roylee.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker.xcodeproj/xcuserdata/roylee.xcuserdatad/xcschemes/PrismaSimpleImagePicker.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker.xcodeproj/xcuserdata/roylee.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | PrismaSimpleImagePicker.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 7D56B5DD1D449BA1009224A5 16 | 17 | primary 18 | 19 | 20 | 7D56B5F11D449BA1009224A5 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/7/24. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(application: UIApplication) { 23 | // 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. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(application: UIApplication) { 28 | // 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. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(application: UIApplication) { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(application: UIApplication) { 37 | // 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. 38 | } 39 | 40 | func applicationWillTerminate(application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/AppIcon.appiconset/AppIcon29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/AppIcon.appiconset/AppIcon29x29@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/AppIcon.appiconset/AppIcon29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/AppIcon.appiconset/AppIcon29x29@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/AppIcon.appiconset/AppIcon40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/AppIcon.appiconset/AppIcon40x40@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/AppIcon.appiconset/AppIcon40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/AppIcon.appiconset/AppIcon40x40@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/AppIcon.appiconset/AppIcon60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/AppIcon.appiconset/AppIcon60x60@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/AppIcon.appiconset/AppIcon60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/AppIcon.appiconset/AppIcon60x60@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "AppIcon29x29@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "29x29", 11 | "idiom" : "iphone", 12 | "filename" : "AppIcon29x29@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "40x40", 17 | "idiom" : "iphone", 18 | "filename" : "AppIcon40x40@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "40x40", 23 | "idiom" : "iphone", 24 | "filename" : "AppIcon40x40@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "60x60", 29 | "idiom" : "iphone", 30 | "filename" : "AppIcon60x60@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "AppIcon60x60@3x.png", 37 | "scale" : "3x" 38 | }, 39 | ], 40 | "info" : { 41 | "version" : 1, 42 | "author" : "xcode" 43 | } 44 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/Oval.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "Oval@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "Oval@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/Oval.imageset/Oval@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/Oval.imageset/Oval@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/Oval.imageset/Oval@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/Oval.imageset/Oval@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/StyleSelected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "StyleSelected.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "StyleSelected@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "StyleSelected@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/StyleSelected.imageset/StyleSelected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/StyleSelected.imageset/StyleSelected.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/StyleSelected.imageset/StyleSelected@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/StyleSelected.imageset/StyleSelected@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/StyleSelected.imageset/StyleSelected@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/StyleSelected.imageset/StyleSelected@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/albums-arrow.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "albums-arrow@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "albums-arrow@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | }, 22 | "properties" : { 23 | "template-rendering-intent" : "original" 24 | } 25 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/albums-arrow.imageset/albums-arrow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/albums-arrow.imageset/albums-arrow@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/albums-arrow.imageset/albums-arrow@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/albums-arrow.imageset/albums-arrow@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/arrows.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "arrows@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "arrows@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/arrows.imageset/arrows@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/arrows.imageset/arrows@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/arrows.imageset/arrows@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/arrows.imageset/arrows@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/back.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "back@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "back@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | }, 22 | "properties" : { 23 | "template-rendering-intent" : "original" 24 | } 25 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/back.imageset/back@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/back.imageset/back@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/back.imageset/back@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/back.imageset/back@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/cross.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "cross@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "cross@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | }, 22 | "properties" : { 23 | "template-rendering-intent" : "original" 24 | } 25 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/cross.imageset/cross@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/cross.imageset/cross@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/cross.imageset/cross@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/cross.imageset/cross@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/facebook-small.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "facebook-small@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/facebook-small.imageset/facebook-small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/facebook-small.imageset/facebook-small@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/facebook.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "facebook@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "facebook@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/facebook.imageset/facebook@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/facebook.imageset/facebook@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/facebook.imageset/facebook@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/facebook.imageset/facebook@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/flash-auto.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "flash-auto@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "flash-auto@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | }, 22 | "properties" : { 23 | "template-rendering-intent" : "original" 24 | } 25 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/flash-auto.imageset/flash-auto@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/flash-auto.imageset/flash-auto@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/flash-auto.imageset/flash-auto@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/flash-auto.imageset/flash-auto@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/flash-on.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "flash-on@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "flash-on@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | }, 22 | "properties" : { 23 | "template-rendering-intent" : "original" 24 | } 25 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/flash-on.imageset/flash-on@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/flash-on.imageset/flash-on@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/flash-on.imageset/flash-on@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/flash-on.imageset/flash-on@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/flash.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "flash@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "flash@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | }, 22 | "properties" : { 23 | "template-rendering-intent" : "original" 24 | } 25 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/flash.imageset/flash@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/flash.imageset/flash@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/flash.imageset/flash@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/flash.imageset/flash@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/flip.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "flip@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "flip@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/flip.imageset/flip@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/flip.imageset/flip@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/flip.imageset/flip@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/flip.imageset/flip@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/instagram-small.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "instagram-small@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/instagram-small.imageset/instagram-small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/instagram-small.imageset/instagram-small@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/instagram.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "instagram@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "instagram@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/instagram.imageset/instagram@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/instagram.imageset/instagram@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/instagram.imageset/instagram@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/instagram.imageset/instagram@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/nocamera.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "nocamera@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "nocamera@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/nocamera.imageset/nocamera@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/nocamera.imageset/nocamera@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/nocamera.imageset/nocamera@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/nocamera.imageset/nocamera@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/ok.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "ok@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "ok@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/ok.imageset/ok@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/ok.imageset/ok@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/ok.imageset/ok@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/ok.imageset/ok@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/photos.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "photos@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "photos@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/photos.imageset/photos@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/photos.imageset/photos@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/photos.imageset/photos@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/photos.imageset/photos@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/rotate-left.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "rotate-left@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "rotate-left@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/rotate-left.imageset/rotate-left@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/rotate-left.imageset/rotate-left@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/rotate-left.imageset/rotate-left@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/rotate-left.imageset/rotate-left@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/rotate-right.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "rotate-right@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "rotate-right@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/rotate-right.imageset/rotate-right@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/rotate-right.imageset/rotate-right@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/rotate-right.imageset/rotate-right@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/rotate-right.imageset/rotate-right@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/save-small.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "save-small@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/save-small.imageset/save-small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/save-small.imageset/save-small@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/save.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "save@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "save@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/save.imageset/save@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/save.imageset/save@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/save.imageset/save@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/save.imageset/save@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/settings.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "settings@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "settings@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | }, 22 | "properties" : { 23 | "template-rendering-intent" : "original" 24 | } 25 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/settings.imageset/settings@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/settings.imageset/settings@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/settings.imageset/settings@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/settings.imageset/settings@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/share-small.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "share-small@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/share-small.imageset/share-small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/share-small.imageset/share-small@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/share.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "share@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "share@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/share.imageset/share@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/share.imageset/share@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/share.imageset/share@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/share.imageset/share@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/vk-small.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "vk-small@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/vk-small.imageset/vk-small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/vk-small.imageset/vk-small@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/vk.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "vk@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "vk@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/vk.imageset/vk@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/vk.imageset/vk@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/vk.imageset/vk@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/vk.imageset/vk@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/watermark.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "watermark@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/watermark.imageset/watermark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/watermark.imageset/watermark@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/weibo-small.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "weibo-small@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/weibo-small.imageset/weibo-small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/weibo-small.imageset/weibo-small@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/weibo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "weibo@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "weibo@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/weibo.imageset/weibo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/weibo.imageset/weibo@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/weibo.imageset/weibo@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/weibo.imageset/weibo@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/weсhat-small.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "weсhat-small@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/weсhat-small.imageset/weсhat-small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/weсhat-small.imageset/weсhat-small@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/weсhat.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "weсhat@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "weсhat@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/weсhat.imageset/weсhat@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/weсhat.imageset/weсhat@2x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Assets.xcassets/weсhat.imageset/weсhat@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/PrismaSimpleImagePicker/Assets.xcassets/weсhat.imageset/weсhat@3x.png -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | Prisma 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UIRequiresFullScreen 34 | 35 | UIStatusBarHidden 36 | 37 | UISupportedInterfaceOrientations 38 | 39 | UIInterfaceOrientationPortrait 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaImagePicker/PickerController/PMImageGroupController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMImageGroupController.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/7/25. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Photos 11 | 12 | class PMImageGroupController: UIViewController, UITableViewDelegate, UITableViewDataSource { 13 | 14 | 15 | @IBOutlet weak var tableView: UITableView! 16 | let topLine: CALayer = CALayer.init() 17 | var groups: [PMGroupModel] = [PMGroupModel]() 18 | var photoGroups: [PHAssetCollection]? = [PHAssetCollection]() 19 | var didSelectGroupAction: ((Int)-> Void)? 20 | 21 | 22 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { 23 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 24 | } 25 | 26 | convenience init() { 27 | var nibNameOrNil = String?("PMImageGroupController") 28 | if NSBundle.mainBundle().pathForResource(nibNameOrNil, ofType: "xib") == nil { 29 | nibNameOrNil = nil 30 | } 31 | self.init(nibName: nibNameOrNil, bundle: nil) 32 | } 33 | 34 | required init?(coder aDecoder: NSCoder) { 35 | fatalError("init(coder:) has not been implemented") 36 | } 37 | 38 | override func viewDidLoad() { 39 | super.viewDidLoad() 40 | 41 | edgesForExtendedLayout = .None 42 | automaticallyAdjustsScrollViewInsets = false 43 | 44 | tableView.registerNib(UINib.init(nibName: "PMImageGroupCell", bundle: nil), forCellReuseIdentifier: "kGroupCellIdfy") 45 | var contentInset = tableView.contentInset 46 | contentInset.bottom = 44 47 | tableView.contentInset = contentInset 48 | 49 | // Top line 50 | let mainScreen: UIScreen = UIScreen.mainScreen() 51 | let frame = CGRectMake(0, -1/mainScreen.scale, mainScreen.bounds.size.width, 1/mainScreen.scale) 52 | topLine.frame = frame 53 | topLine.backgroundColor = UIColor.whiteColor().CGColor 54 | topLine.shadowOffset = CGSizeMake(0, frame.size.height) 55 | topLine.shadowRadius = 1 56 | topLine.shadowOpacity = 1 57 | topLine.shadowColor = UIColor.lightGrayColor().CGColor 58 | 59 | view.layer.masksToBounds = true 60 | view.layer.addSublayer(topLine) 61 | 62 | // PHAssetCollection to Model 63 | for collection in photoGroups! { 64 | let groupModel = PMGroupModel.groupModelFromPHAssetCollection(collection) 65 | groups.append(groupModel) 66 | } 67 | } 68 | 69 | override func viewDidLayoutSubviews() { 70 | topLine.removeFromSuperlayer() 71 | view.layer.addSublayer(topLine) 72 | } 73 | 74 | 75 | // MARK: UITableView M 76 | 77 | func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { 78 | return UIScreen.mainScreen().bounds.size.width/320 * 80 79 | } 80 | 81 | func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 82 | return groups.count 83 | } 84 | 85 | func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 86 | let cell = tableView.dequeueReusableCellWithIdentifier("kGroupCellIdfy", forIndexPath: indexPath) as! PMImageGroupCell 87 | 88 | let groupModel = groups[indexPath.item] 89 | cell.configGroupCell(groupModel) 90 | 91 | return cell 92 | } 93 | 94 | func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 95 | if let doneAction = didSelectGroupAction { 96 | doneAction(indexPath.item) 97 | } 98 | } 99 | 100 | override func prefersStatusBarHidden() -> Bool { 101 | return true 102 | } 103 | 104 | override func didReceiveMemoryWarning() { 105 | super.didReceiveMemoryWarning() 106 | // Dispose of any resources that can be recreated. 107 | } 108 | 109 | 110 | /* 111 | // MARK: - Navigation 112 | 113 | // In a storyboard-based application, you will often want to do a little preparation before navigation 114 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 115 | // Get the new view controller using segue.destinationViewController. 116 | // Pass the selected object to the new view controller. 117 | } 118 | */ 119 | 120 | } 121 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaImagePicker/PickerController/PMImageGroupController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaImagePicker/PickerController/PMImagePickerController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMImagePickerController.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/7/24. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Photos 11 | 12 | @objc protocol PMImagePickerControllerDelegate: NSObjectProtocol { 13 | /** 14 | Call when tap `Use` button of the picker view controller 15 | 16 | - parameter picker: The view controller of class PMImagePickerController 17 | - parameter image: An cropped image which displayed in the top header after edit 18 | */ 19 | optional func imagePickerController(picker: PMImagePickerController, didFinishPickingImage image: UIImage) 20 | 21 | /** 22 | Call when tap `Use` button of the picker view controller 23 | 24 | - parameter picker: The view controller of class PMImagePickerController 25 | - parameter originalImage: An original image which displayed in the top header 26 | - parameter selectedRect: A rect displayed of the header 27 | - parameter zoomScale: ZoomScale of the image 28 | */ 29 | optional func imagePickerController(picker: PMImagePickerController, didFinishPickingImage originalImage: UIImage, selectedRect: CGRect, zoomScale:CGFloat) 30 | 31 | /** 32 | Call when tap `Cancel` button of the picker view controller 33 | 34 | - parameter picker: The view controller of class PMImagePickerController 35 | */ 36 | optional func imagePickerControllerDidCancel(picker: PMImagePickerController) 37 | } 38 | 39 | class PMImagePickerController: UINavigationController { 40 | 41 | private var _photoGroups: [PHAssetCollection]? = [PHAssetCollection]() 42 | private var _photoAssets: [PHAsset]? = [PHAsset]() 43 | weak var pmDelegate: PMImagePickerControllerDelegate? 44 | var photoGroups: [PHAssetCollection] { 45 | set { 46 | _photoGroups = newValue 47 | let rootVC = viewControllers[0] as? PMImageViewController 48 | rootVC?.photoGroups = newValue 49 | } 50 | get { 51 | return _photoGroups! 52 | } 53 | } 54 | var photoAssets: [PHAsset] { 55 | set { 56 | _photoAssets = newValue 57 | let rootVC = viewControllers[0] as? PMImageViewController 58 | rootVC?.photoAssets = newValue 59 | } 60 | get { 61 | return _photoAssets! 62 | } 63 | } 64 | 65 | init() { 66 | let rootVC = PMImageViewController(nibName: "PMImageViewController", bundle: nil) 67 | super.init(rootViewController: rootVC) 68 | } 69 | 70 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { 71 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 72 | } 73 | 74 | required init?(coder aDecoder: NSCoder) { 75 | super.init(coder: aDecoder) 76 | fatalError("init(coder:) has not been implemented") 77 | } 78 | 79 | override func viewDidLoad() { 80 | super.viewDidLoad() 81 | 82 | // Init navigation bar 83 | let bgImage = UIImage.imageWithColor(UIColor.whiteColor(), size: CGSizeMake(UIScreen.mainScreen().bounds.size.width, 44)) 84 | navigationBar.tintColor = UIColor.blackColor() 85 | navigationBar.setBackgroundImage(bgImage, forBarPosition: UIBarPosition.Top, barMetrics: UIBarMetrics.Default) 86 | navigationBar.shadowImage = UIImage.init() 87 | } 88 | 89 | override func didReceiveMemoryWarning() { 90 | super.didReceiveMemoryWarning() 91 | } 92 | /* 93 | // MARK: - Navigation 94 | 95 | // In a storyboard-based application, you will often want to do a little preparation before navigation 96 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 97 | // Get the new view controller using segue.destinationViewController. 98 | // Pass the selected object to the new view controller. 99 | } 100 | */ 101 | 102 | } 103 | 104 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaImagePicker/PickerController/PMImageViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaImagePicker/PickerHelper/PMDeviceOrientation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMDeviceOrientation.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/7/29. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import CoreMotion 11 | import AVFoundation 12 | 13 | class PMDeviceOrientation: NSObject { 14 | 15 | var motionManager: CMMotionManager = CMMotionManager() 16 | 17 | override init() { 18 | super.init() 19 | setupMotionManger() 20 | } 21 | 22 | // MARK: Actual orientation 23 | func orientation() -> UIDeviceOrientation { 24 | return actualDeviceOrientationFromAccelerometer() 25 | } 26 | 27 | func deviceOrientationMatchesInterfaceOrientation() -> Bool { 28 | return orientation() == UIDevice.currentDevice().orientation 29 | } 30 | 31 | /// Change UIDeviceOrientation to AVCaptureVideoOrientation 32 | class func avOrientationFromDeviceOrientation(deviceOrientation: UIDeviceOrientation) -> AVCaptureVideoOrientation { 33 | var result = AVCaptureVideoOrientation.Portrait 34 | if deviceOrientation == UIDeviceOrientation.LandscapeLeft { 35 | result = .LandscapeRight 36 | }else if deviceOrientation == UIDeviceOrientation.LandscapeRight { 37 | result = .LandscapeLeft 38 | }else if deviceOrientation == UIDeviceOrientation.PortraitUpsideDown { 39 | result = .PortraitUpsideDown 40 | } 41 | return result 42 | } 43 | 44 | // MARK: Privatte 45 | private func setupMotionManger() { 46 | UIDevice.currentDevice().beginGeneratingDeviceOrientationNotifications() 47 | motionManager.accelerometerUpdateInterval = 0.005 48 | motionManager.startAccelerometerUpdates() 49 | } 50 | 51 | private func teardownMotionManager() { 52 | UIDevice.currentDevice().endGeneratingDeviceOrientationNotifications() 53 | motionManager.stopAccelerometerUpdates() 54 | } 55 | 56 | private func actualDeviceOrientationFromAccelerometer() -> UIDeviceOrientation { 57 | let acceleration = motionManager.accelerometerData!.acceleration 58 | if acceleration.z < -0.75 { 59 | return UIDeviceOrientation.FaceUp 60 | } 61 | 62 | if acceleration.z > 0.75 { 63 | return UIDeviceOrientation.FaceDown 64 | } 65 | 66 | let scaling = 1.0 / (fabs(acceleration.x) + fabs(acceleration.y)) 67 | 68 | let x = acceleration.x * scaling 69 | let y = acceleration.y * scaling 70 | 71 | if x < -0.5 { 72 | return UIDeviceOrientation.LandscapeLeft 73 | } 74 | 75 | if x > 0.5 { 76 | return UIDeviceOrientation.LandscapeRight 77 | } 78 | 79 | if y > 0.5 { 80 | return UIDeviceOrientation.PortraitUpsideDown 81 | } 82 | 83 | return UIDeviceOrientation.Portrait 84 | } 85 | 86 | deinit { 87 | teardownMotionManager() 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaImagePicker/PickerHelper/PMImageManger.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMImageManger.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/7/29. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AVFoundation 11 | import AssetsLibrary 12 | import Photos 13 | import CoreImage 14 | import Accelerate 15 | 16 | 17 | public enum RotateOrientation : Int { 18 | 19 | case Up // default orientation 20 | case Down // 180 deg rotation 21 | case Left // 90 deg CCW 22 | case Right // 90 deg CW 23 | case UpMirrored // as above but image mirrored along other axis. horizontal flip 24 | case DownMirrored // horizontal flip 25 | case LeftMirrored // vertical flip 26 | case RightMirrored // vertical flip 27 | } 28 | 29 | class PMImageManger: NSObject { 30 | /// Camera about 31 | 32 | // MARK: Authorizations 33 | /// Capture authorization 34 | class func captureAuthorization(shouldCapture: ((Bool)-> Void)!) { 35 | 36 | let captureStatus = AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo) 37 | switch captureStatus { 38 | case.NotDetermined: 39 | AVCaptureDevice.requestAccessForMediaType(AVMediaTypeVideo, completionHandler: { (granted: Bool) -> Void in 40 | runOnMainQuene({ () -> Void in 41 | shouldCapture(granted) 42 | }) 43 | }) 44 | break 45 | case.Authorized: 46 | shouldCapture(true) 47 | break 48 | default: 49 | shouldCapture(false) 50 | break 51 | } 52 | } 53 | 54 | // Run on main quene 55 | class func runOnMainQuene(callBack: (()->Void)?) { 56 | if NSThread.currentThread().isMainThread { 57 | if let call = callBack { 58 | call() 59 | } 60 | }else { 61 | dispatch_async(dispatch_get_main_queue(), { 62 | if let call = callBack { 63 | call() 64 | } 65 | }) 66 | } 67 | } 68 | 69 | /// Crop the image to target size, default crop in the middle 70 | class func cropImageAffterCapture(originImage: UIImage, toSize: CGSize) -> UIImage { 71 | 72 | let ratio = toSize.height/toSize.width 73 | let width = originImage.size.width 74 | let height = width * ratio 75 | let x = CGFloat(0) 76 | let y = (originImage.size.height - height)/2 77 | 78 | let finalRect = CGRectMake(x, y, width, height) 79 | let croppedImage = UIImage.init(CGImage: CGImageCreateWithImageInRect(originImage.CGImage!, finalRect)!, scale: originImage.scale, orientation: originImage.imageOrientation) 80 | 81 | return croppedImage 82 | } 83 | 84 | /// Crop the image to target rect 85 | class func cropImageToRect(originImage: UIImage, toRect: CGRect) -> UIImage { 86 | 87 | let croppedImage = UIImage.init(CGImage: CGImageCreateWithImageInRect(originImage.CGImage!, toRect)!, scale: originImage.scale, orientation: originImage.imageOrientation) 88 | 89 | return croppedImage 90 | } 91 | 92 | /// Photolibrary authorization 93 | class func photoAuthorization(canGoAssets: ((Bool)-> Void)!) { 94 | 95 | let PhotoStatus: PHAuthorizationStatus = PHPhotoLibrary.authorizationStatus() 96 | switch (PhotoStatus) { 97 | case .NotDetermined: 98 | PHPhotoLibrary.requestAuthorization { (status: PHAuthorizationStatus) in 99 | dispatch_async(dispatch_get_main_queue(), { 100 | switch (status) { 101 | case .Authorized: 102 | canGoAssets(true) 103 | break 104 | default: 105 | canGoAssets(false) 106 | break 107 | } 108 | }) 109 | } 110 | break 111 | case .Authorized: 112 | canGoAssets(true) 113 | break 114 | default: 115 | canGoAssets(false) 116 | break 117 | } 118 | } 119 | 120 | // MARK: Photo libiary 121 | /// Get photo albums 122 | class func photoLibrarys() -> [PHAssetCollection] { 123 | var photoGroups:[PHAssetCollection] = [PHAssetCollection]() 124 | 125 | // Camera 126 | let cameraRoll: PHAssetCollection = (PHAssetCollection.fetchAssetCollectionsWithType(.SmartAlbum, subtype: .SmartAlbumUserLibrary, options: nil).lastObject as? PHAssetCollection)! 127 | if cameraRoll.photosCount > 0 { 128 | photoGroups.append(cameraRoll) 129 | } 130 | 131 | // Favorites 132 | let favorites: PHFetchResult = PHAssetCollection.fetchAssetCollectionsWithType(.SmartAlbum, subtype: .SmartAlbumFavorites, options: nil) 133 | favorites.enumerateObjectsWithOptions(.Reverse) { (obj, index: Int, stop: UnsafeMutablePointer) in 134 | let collection = obj as! PHAssetCollection 135 | guard collection.photosCount > 0 else { 136 | return 137 | } 138 | photoGroups.append(collection) 139 | } 140 | 141 | // ScreenShots 142 | if #available(iOS 9.0, *) { 143 | let screenShots: PHFetchResult = PHAssetCollection.fetchAssetCollectionsWithType(.SmartAlbum, subtype: .SmartAlbumScreenshots, options: nil) 144 | screenShots.enumerateObjectsWithOptions(.Reverse) { (obj, index: Int, stop: UnsafeMutablePointer) in 145 | let collection = obj as! PHAssetCollection 146 | guard collection.photosCount > 0 else { 147 | return 148 | } 149 | photoGroups.append(collection) 150 | } 151 | } 152 | 153 | // User photos 154 | let assetCollections: PHFetchResult = PHAssetCollection.fetchAssetCollectionsWithType(.Album, subtype: .AlbumRegular, options: nil) 155 | assetCollections.enumerateObjectsWithOptions(.Reverse) { (obj, index: Int, stop: UnsafeMutablePointer) in 156 | let collection = obj as! PHAssetCollection 157 | guard collection.photosCount > 0 else { 158 | return 159 | } 160 | photoGroups.append(collection) 161 | } 162 | 163 | return photoGroups 164 | } 165 | 166 | /// Get photos from an album 167 | class func photoAssetsForAlbum(collection: PHAssetCollection) -> [PHAsset] { 168 | var photoAssets:[PHAsset] = [PHAsset]() 169 | 170 | let asstes: PHFetchResult = PHAsset.fetchAssetsInAssetCollection(collection, options: nil) 171 | asstes.enumerateObjectsWithOptions(NSEnumerationOptions.Reverse) { (obj, index: Int, stop: UnsafeMutablePointer) in 172 | photoAssets.append(obj as! PHAsset) 173 | } 174 | return photoAssets 175 | } 176 | 177 | // Get image from a PHAsset 178 | class func imageFromAsset(asset: PHAsset, isOriginal original: Bool, toSize: CGSize?, resultHandler: (UIImage?)->Void) { 179 | let options = PHImageRequestOptions() 180 | options.synchronous = true 181 | options.resizeMode = .Fast 182 | options.deliveryMode = .FastFormat 183 | 184 | var size = CGSizeMake(100, 100) 185 | if original { 186 | size = CGSizeMake(CGFloat(asset.pixelWidth), CGFloat(asset.pixelHeight)) 187 | }else if let _toSize = toSize { 188 | size = _toSize 189 | } 190 | PHImageManager.defaultManager().requestImageForAsset(asset, targetSize: size, contentMode: PHImageContentMode.AspectFill, options: options) { (image: UIImage?, info: [NSObject : AnyObject]?) in 191 | resultHandler(image) 192 | } 193 | } 194 | 195 | // Translate degress to image orientation 196 | class func imageOrientationFromDegress(angle: CGFloat) -> UIImageOrientation { 197 | var orientation = UIImageOrientation.Up 198 | let ratio = (angle/CGFloat(M_PI/2))%4 199 | switch ratio { 200 | case 0: 201 | orientation = .Up 202 | break 203 | case 1, -3: 204 | orientation = .Right 205 | break 206 | case 2, -2: 207 | orientation = .Down 208 | break 209 | case 3, -1: 210 | orientation = .Left 211 | break 212 | default: 213 | orientation = .Up 214 | break 215 | } 216 | return orientation 217 | } 218 | 219 | } 220 | 221 | // MARK: UIImage ectension 222 | extension UIImage { 223 | // Get a image with color 224 | func imageWithColor(color: UIColor) -> UIImage { 225 | UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale) 226 | let context = UIGraphicsGetCurrentContext() 227 | CGContextTranslateCTM(context!, 0, self.size.height) 228 | CGContextScaleCTM(context!, 1.0, -1.0) 229 | CGContextSetBlendMode(context!, CGBlendMode.Normal) 230 | let rect = CGRectMake(0, 0, self.size.width, self.size.height) 231 | CGContextClipToMask(context!, rect, self.CGImage!) 232 | color.setFill() 233 | CGContextFillRect(context!, rect) 234 | let newImage = UIGraphicsGetImageFromCurrentImageContext() 235 | UIGraphicsEndImageContext() 236 | return newImage! 237 | } 238 | 239 | // Get a image with color & size 240 | class func imageWithColor(color: UIColor, size: CGSize) -> UIImage { 241 | let rect = CGRectMake(0, 0, size.width, size.height) 242 | UIGraphicsBeginImageContext(rect.size) 243 | let context = UIGraphicsGetCurrentContext() 244 | CGContextSetFillColorWithColor(context!, color.CGColor) 245 | CGContextFillRect(context!, rect) 246 | let image = UIGraphicsGetImageFromCurrentImageContext() 247 | UIGraphicsEndImageContext() 248 | return image! 249 | } 250 | 251 | /** 252 | Method to fix the orientation of an image.(The orientation of an image is just the orientation for the possion when take a photo) 253 | An image after capture, the orientation is not the correct possion(roated 90 degress), owing to the position of sensor. And the default possion of iPhone is landscape & home button on the right. 254 | AVPreviewLayer has fixed the possion of the image, so it display a correct image. But when we handle the image, the image is just original(not on the corrent possion). 255 | So, if we make a capture portrait, Actually the image landscape left and the orientation is right. 256 | e.g. 257 | 258 | | _ | __________ 259 | | |_ | --> | 260 | | | | --> |__|___ | So, the image is `|_|__` 261 | | __ | __________| And orientation is right(the sensor orientation when take a photo) 262 | 263 | - returns: An image has been fixed oriention 264 | */ 265 | func fixOrientation() -> UIImage { 266 | return fixOrientation(imageOrientation) 267 | } 268 | 269 | /** 270 | Rotate image to the target orientation. 271 | 272 | - parameter rotateOrientation: target orientation 273 | 274 | - returns: An image has been changed to the target orientaion 275 | */ 276 | func rotateImageTo(rotateOrientation: RotateOrientation) -> UIImage { 277 | 278 | var imageOrientation = UIImageOrientation.Up 279 | switch rotateOrientation { 280 | case .Up: 281 | imageOrientation = .Up 282 | break 283 | case .UpMirrored: 284 | imageOrientation = .UpMirrored 285 | break 286 | case .Left: 287 | imageOrientation = .Right 288 | break 289 | case .LeftMirrored: 290 | imageOrientation = .RightMirrored 291 | break 292 | case .Right: 293 | imageOrientation = .Left 294 | break 295 | case .RightMirrored: 296 | imageOrientation = .LeftMirrored 297 | break 298 | case .Down: 299 | imageOrientation = .Down 300 | break 301 | case .DownMirrored: 302 | imageOrientation = .DownMirrored 303 | break 304 | } 305 | 306 | return fixOrientation(imageOrientation) 307 | } 308 | 309 | func rotateImageFromInterfaceOrientation(orientation: UIDeviceOrientation) -> UIImage { 310 | var rotateOrientation = RotateOrientation.Up 311 | switch orientation { 312 | case .Portrait: 313 | rotateOrientation = .Up 314 | break 315 | case .LandscapeLeft: 316 | rotateOrientation = .Right 317 | break 318 | case .LandscapeRight: 319 | rotateOrientation = .Left 320 | break 321 | case .PortraitUpsideDown: 322 | rotateOrientation = .Down 323 | break 324 | default: 325 | rotateOrientation = .Up 326 | break 327 | } 328 | return rotateImageTo(rotateOrientation) 329 | } 330 | 331 | func fixOrientation(imageOrientation: UIImageOrientation) -> UIImage { 332 | if imageOrientation == UIImageOrientation.Up { 333 | return self 334 | } 335 | 336 | var transform: CGAffineTransform = CGAffineTransformIdentity 337 | 338 | switch imageOrientation { 339 | case UIImageOrientation.Down, UIImageOrientation.DownMirrored: 340 | transform = CGAffineTransformTranslate(transform, size.width, size.height) 341 | transform = CGAffineTransformRotate(transform, CGFloat(M_PI)) 342 | break 343 | case UIImageOrientation.Left, UIImageOrientation.LeftMirrored: 344 | transform = CGAffineTransformTranslate(transform, size.width, 0) 345 | transform = CGAffineTransformRotate(transform, CGFloat(M_PI_2)) 346 | break 347 | case UIImageOrientation.Right, UIImageOrientation.RightMirrored: 348 | transform = CGAffineTransformTranslate(transform, 0, size.height) 349 | transform = CGAffineTransformRotate(transform, CGFloat(-M_PI_2)) 350 | break 351 | case UIImageOrientation.Up, UIImageOrientation.UpMirrored: 352 | break 353 | } 354 | 355 | switch imageOrientation { 356 | case UIImageOrientation.UpMirrored, UIImageOrientation.DownMirrored: 357 | CGAffineTransformTranslate(transform, size.width, 0) 358 | CGAffineTransformScale(transform, -1, 1) 359 | break 360 | case UIImageOrientation.LeftMirrored, UIImageOrientation.RightMirrored: 361 | CGAffineTransformTranslate(transform, size.height, 0) 362 | CGAffineTransformScale(transform, -1, 1) 363 | case UIImageOrientation.Up, UIImageOrientation.Down, UIImageOrientation.Left, UIImageOrientation.Right: 364 | break 365 | } 366 | 367 | let ctx: CGContextRef = CGBitmapContextCreate(nil, Int(size.width), Int(size.height), CGImageGetBitsPerComponent(CGImage!), 0, CGImageGetColorSpace(CGImage!)!, CGImageAlphaInfo.PremultipliedLast.rawValue)! 368 | 369 | CGContextConcatCTM(ctx, transform) 370 | 371 | switch imageOrientation { 372 | case UIImageOrientation.Left, UIImageOrientation.LeftMirrored, UIImageOrientation.Right, UIImageOrientation.RightMirrored: 373 | CGContextDrawImage(ctx, CGRectMake(0, 0, size.height, size.width), CGImage!) 374 | break 375 | default: 376 | CGContextDrawImage(ctx, CGRectMake(0, 0, size.width, size.height), CGImage!) 377 | break 378 | } 379 | 380 | let cgImage: CGImageRef = CGBitmapContextCreateImage(ctx)! 381 | 382 | return UIImage(CGImage: cgImage) 383 | } 384 | } 385 | 386 | 387 | // MARK: UIColor ectension 388 | extension UIColor { 389 | 390 | class func RGBColor(red: CGFloat, green: CGFloat, blue: CGFloat) -> UIColor { 391 | return RGBAlphaColor(red, green: green, blue: blue, alpha: 1) 392 | } 393 | 394 | class func RGBAlphaColor(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) -> UIColor { 395 | return UIColor.init(red: red/255.0, green: green/255.0, blue: blue/255.0, alpha: alpha) 396 | } 397 | 398 | } 399 | 400 | 401 | // MARK: UIDevice orientation 402 | extension UIDevice { 403 | 404 | } 405 | 406 | 407 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaImagePicker/PickerModel/PMGroupModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMGroupModel.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/7/25. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Photos 11 | 12 | class PMGroupModel: NSObject { 13 | 14 | var image: UIImage? 15 | var title: String? 16 | var content: String? 17 | 18 | override init() { 19 | super.init() 20 | } 21 | 22 | convenience init(image: UIImage?, title: String?, content: String?) { 23 | self.init() 24 | self.image = image 25 | self.title = title 26 | self.content = content 27 | } 28 | 29 | class func groupModelFromPHAssetCollection(collection: PHAssetCollection) -> PMGroupModel { 30 | 31 | var image: UIImage? = nil 32 | let title = collection.localizedTitle 33 | let content = collection.photosCount 34 | 35 | let assets: PHFetchResult = PHAsset.fetchAssetsInAssetCollection(collection, options: nil) 36 | let asset = assets.firstObject as? PHAsset 37 | 38 | let options = PHImageRequestOptions() 39 | options.synchronous = true 40 | options.resizeMode = .Fast 41 | options.deliveryMode = .FastFormat 42 | 43 | if let _asset = asset { 44 | let size: CGSize = CGSizeMake(150, 150) 45 | PHImageManager.defaultManager().requestImageForAsset(_asset, targetSize: size, contentMode: PHImageContentMode.AspectFill, options: options) { (_image: UIImage?, info: [NSObject : AnyObject]?) in 46 | image = _image 47 | } 48 | } 49 | 50 | let model = PMGroupModel.init(image: image, title: title, content: String(content)) 51 | return model 52 | } 53 | } 54 | 55 | 56 | extension PHAssetCollection { 57 | var photosCount: Int { 58 | let fetchOptions = PHFetchOptions() 59 | fetchOptions.predicate = NSPredicate(format: "mediaType == %d", PHAssetMediaType.Image.rawValue) 60 | let result = PHAsset.fetchAssetsInAssetCollection(self, options: fetchOptions) 61 | return result.count 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaImagePicker/PickerView/PMImageGroupCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMImageGroupCell.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/7/25. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Photos 11 | 12 | class PMImageGroupCell: UITableViewCell { 13 | 14 | 15 | @IBOutlet weak var groupCover: UIImageView! 16 | @IBOutlet weak var groupTitle: UILabel! 17 | @IBOutlet weak var groupContent: UILabel! 18 | 19 | 20 | override func awakeFromNib() { 21 | super.awakeFromNib() 22 | // Initialization code 23 | selectedBackgroundView = UIView.init(frame: self.bounds) 24 | selectedBackgroundView!.backgroundColor = UIColor.init(white: 0.85, alpha: 1) 25 | } 26 | 27 | func configGroupCell(group : PMGroupModel) { 28 | groupCover.image = group.image 29 | groupTitle.text = group.title 30 | groupContent.text = group.content 31 | } 32 | 33 | 34 | override func setSelected(selected: Bool, animated: Bool) { 35 | super.setSelected(selected, animated: animated) 36 | 37 | // Configure the view for the selected state 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaImagePicker/PickerView/PMImageGroupCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 40 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaImagePicker/PickerView/PMPhotoGridView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMPhotoGridView.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/7/26. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PMPhotoGridView: UIView { 12 | 13 | var lineWidth: CGFloat = 1.0/UIScreen.mainScreen().scale 14 | var lineOffset: CGFloat = (1.0/UIScreen.mainScreen().scale)/2 15 | let screenScale: CGFloat = UIScreen.mainScreen().scale 16 | var lineBgWidth: CGFloat = 5 17 | var lineColor: UIColor = UIColor.init(white: 1.0, alpha: 0.45) 18 | var lineBgColor: UIColor = UIColor.init(white: 0.65, alpha: 0.07) 19 | 20 | 21 | override var frame: CGRect { 22 | didSet { 23 | setNeedsDisplay() 24 | } 25 | } 26 | 27 | override init(frame: CGRect) { 28 | super.init(frame: frame) 29 | backgroundColor = UIColor.clearColor() 30 | } 31 | 32 | required init?(coder aDecoder: NSCoder) { 33 | fatalError("init(coder:) has not been implemented") 34 | } 35 | 36 | // Only override drawRect: if you perform custom drawing. 37 | // An empty implementation adversely affects performance during animation. 38 | override func drawRect(rect: CGRect) { 39 | 40 | let context = UIGraphicsGetCurrentContext() 41 | 42 | drawLine(context!, color: lineBgColor, width: lineBgWidth) 43 | CGContextSaveGState(context!) 44 | drawLine(context!, color: lineColor, width: lineWidth) 45 | } 46 | 47 | func drawLine(context: CGContext, color: UIColor, width: CGFloat) { 48 | let width1 = CGFloatPixelRound(bounds.size.width/3) 49 | let width2 = CGFloatPixelRound(bounds.size.width/3 * 2) 50 | let height1 = CGFloatPixelRound(bounds.size.height/3) 51 | let height2 = CGFloatPixelRound(bounds.size.height/3 * 2) 52 | 53 | // H line 1 54 | CGContextSetStrokeColorWithColor(context, color.CGColor) 55 | CGContextMoveToPoint(context, 0, height1 + lineOffset) 56 | CGContextAddLineToPoint(context, bounds.size.width, height1 + lineOffset) 57 | CGContextSetLineWidth(context, width) 58 | CGContextStrokePath(context) 59 | 60 | CGContextSaveGState(context) 61 | 62 | // H line 2 63 | CGContextSetStrokeColorWithColor(context, color.CGColor) 64 | CGContextMoveToPoint(context, 0, height2 + lineOffset) 65 | CGContextAddLineToPoint(context, bounds.size.width, height2 + lineOffset) 66 | CGContextSetLineWidth(context, width) 67 | CGContextStrokePath(context) 68 | 69 | CGContextRestoreGState(context) 70 | CGContextSaveGState(context) 71 | 72 | 73 | // V line 1 74 | CGContextSetStrokeColorWithColor(context, color.CGColor) 75 | CGContextMoveToPoint(context, width1 + lineOffset, 0) 76 | CGContextAddLineToPoint(context, width1 + lineOffset, bounds.size.height) 77 | CGContextSetLineWidth(context, width) 78 | CGContextStrokePath(context) 79 | 80 | CGContextRestoreGState(context) 81 | CGContextSaveGState(context) 82 | 83 | // V line 2 84 | CGContextSetStrokeColorWithColor(context, color.CGColor) 85 | CGContextMoveToPoint(context, width2 + lineOffset, 0) 86 | CGContextAddLineToPoint(context, width2 + lineOffset, bounds.size.height) 87 | CGContextSetLineWidth(context, width) 88 | CGContextStrokePath(context) 89 | } 90 | 91 | func CGFloatPixelRound(value: CGFloat) -> CGFloat { 92 | let scale = screenScale 93 | return round(value * scale) / scale 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaImagePicker/PickerView/PMPhotoHeaderItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMPhotoHeaderItem.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/7/26. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | class PMPhotoHeaderItem: UIScrollView, UIScrollViewDelegate { 13 | 14 | var imageContainerView: UIView = UIView.init() 15 | var imageView: UIImageView = UIImageView.init() 16 | var selectedRect: CGRect = CGRectZero 17 | var targetZoomScale: CGFloat = 1.0 18 | 19 | override var frame: CGRect { 20 | didSet { 21 | bounds.origin = CGPointZero // reset zero origin to fit the adjust effect of scroll view 22 | imageContainerView.frame = bounds 23 | imageView.frame = imageContainerView.bounds 24 | resetSubViews() 25 | } 26 | } 27 | var scrollViewDidZoom: ((scrollView: UIScrollView)->Void)? 28 | var scrollViewBeganDragging: ((scrollView: UIScrollView)->Void)? 29 | var scrollViewEndDragging: ((scrollView: UIScrollView)->Void)? 30 | 31 | 32 | override init(frame: CGRect) { 33 | super.init(frame: frame) 34 | configSubviews() 35 | } 36 | 37 | required init?(coder aDecoder: NSCoder) { 38 | fatalError("init(coder:) has not been implemented") 39 | } 40 | 41 | func configSubviews() { 42 | 43 | delegate = self 44 | bouncesZoom = true 45 | maximumZoomScale = 3 46 | multipleTouchEnabled = true 47 | bounces = true 48 | alwaysBounceVertical = true 49 | alwaysBounceHorizontal = true 50 | showsVerticalScrollIndicator = false 51 | showsHorizontalScrollIndicator = false 52 | 53 | imageContainerView.frame = bounds 54 | imageContainerView.clipsToBounds = true 55 | imageContainerView.backgroundColor = UIColor.whiteColor() 56 | imageView.clipsToBounds = true 57 | imageContainerView.addSubview(imageView) 58 | addSubview(imageContainerView) 59 | 60 | let doubleTap = UITapGestureRecognizer.init(target: self, action: #selector(PMPhotoHeaderItem.doubleTap(_:))) 61 | doubleTap.numberOfTapsRequired = 2 62 | addGestureRecognizer(doubleTap) 63 | } 64 | 65 | /** 66 | Set the image of content image view. And scroll to target rect. 67 | If parameter zoomScale is not 1, the target rect `scrollToRect` should be the rect with image coordinate 68 | 69 | - parameter image: An image set to display 70 | - parameter scrollToRect: Target rect to show the image view 71 | - parameter zoomScale: Target zoomScale 72 | */ 73 | func setImage(image: UIImage, scrollToRect: CGRect, zoomScale: CGFloat) { 74 | imageView.image = image 75 | selectedRect = scrollToRect 76 | targetZoomScale = zoomScale 77 | // Reset contentSize 78 | resetSubViews() 79 | } 80 | 81 | // MARK: Private 82 | 83 | @objc private func doubleTap(tap: UITapGestureRecognizer) { 84 | zoomOutView(tap) 85 | // zoomInView(tap) 86 | } 87 | 88 | private func zoomInView(tap: UITapGestureRecognizer) { 89 | if zoomScale > 1 { 90 | setZoomScale(1, animated: true) 91 | } else { 92 | let touchPoint = tap.locationInView(imageView) 93 | let newZoomScale = maximumZoomScale 94 | let xsize = bounds.size.width / newZoomScale 95 | let ysize = bounds.size.height / newZoomScale 96 | 97 | zoomToRect(CGRectMake(touchPoint.x - xsize/2, touchPoint.y - ysize/2, xsize, ysize), animated: true) 98 | } 99 | } 100 | 101 | private func zoomOutView(tap: UITapGestureRecognizer) { 102 | guard zoomScale > 1 else { 103 | return 104 | } 105 | zoomScale = 1 106 | resetSubViews() 107 | } 108 | 109 | private func resetSubViews() { 110 | if let image = imageView.image { 111 | let ratio = image.size.width/image.size.height 112 | let const = bounds.size.width/bounds.size.height 113 | if ratio > const { 114 | contentSize = CGSizeMake(ratio * bounds.size.height, bounds.size.height) 115 | }else { 116 | contentSize = CGSizeMake(bounds.size.width, bounds.size.width/ratio) 117 | } 118 | var frame = imageContainerView.frame 119 | frame.size = contentSize 120 | imageContainerView.frame = frame 121 | imageView.frame = imageContainerView.bounds 122 | 123 | // scroll to target rect 124 | var fitRect = CGRectMake((contentSize.width - bounds.size.width)/2, (contentSize.height - bounds.size.height)/2, bounds.size.width, bounds.size.height) 125 | if !CGRectEqualToRect(selectedRect, CGRectZero) { 126 | fitRect = selectedRect 127 | } 128 | 129 | // zoom if need 130 | if targetZoomScale != 1 { 131 | let contentSize = CGSizeApplyAffineTransform(self.contentSize, CGAffineTransformMakeScale(targetZoomScale, targetZoomScale)) 132 | fitRect.origin.x = fitRect.origin.x * (contentSize.width/image.size.width) 133 | fitRect.origin.y = fitRect.origin.y * (contentSize.height/image.size.height) 134 | 135 | fitRect = CGRectApplyAffineTransform(fitRect, CGAffineTransformMakeScale(1.0/targetZoomScale, 1.0/targetZoomScale)) 136 | zoomToRect(fitRect, animated: false) 137 | }else { 138 | scrollRectToVisible(fitRect, animated: false) 139 | } 140 | } 141 | } 142 | 143 | // MARK: Zoom 144 | func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? { 145 | return imageContainerView 146 | } 147 | 148 | func scrollViewDidZoom(scrollView: UIScrollView) { 149 | let subView = imageContainerView 150 | 151 | var offsetX = CGFloat(0) 152 | if scrollView.bounds.size.width > scrollView.contentSize.width { 153 | offsetX = (scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5 154 | } 155 | 156 | var offsetY = CGFloat(0) 157 | if scrollView.bounds.size.height > scrollView.contentSize.height { 158 | offsetY = (scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5 159 | } 160 | 161 | subView.center = CGPointMake(scrollView.contentSize.width * 0.5 + offsetX, 162 | scrollView.contentSize.height * 0.5 + offsetY) 163 | 164 | if let action = scrollViewDidZoom { 165 | action(scrollView: scrollView) 166 | } 167 | } 168 | 169 | 170 | // MARK: UIScrollView M 171 | 172 | func scrollViewWillBeginDragging(scrollView: UIScrollView) { 173 | if let drag = scrollViewBeganDragging { 174 | drag(scrollView: self) 175 | } 176 | } 177 | 178 | func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) { 179 | if let endDrag = scrollViewEndDragging { 180 | endDrag(scrollView: self) 181 | } 182 | } 183 | 184 | 185 | /* 186 | // Only override drawRect: if you perform custom drawing. 187 | // An empty implementation adversely affects performance during animation. 188 | override func drawRect(rect: CGRect) { 189 | // Drawing code 190 | } 191 | */ 192 | 193 | } 194 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaImagePicker/PickerView/PMPhotoHeaderView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMPhotoHeaderView.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/7/25. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | private var kContentOffsetContext = 0 12 | 13 | class PMPhotoHeaderView: UIView { 14 | 15 | var imageView: PMPhotoHeaderItem = PMPhotoHeaderItem.init() 16 | var tapAction: ((view: PMPhotoHeaderView)->Void)? 17 | var gridMask: PMPhotoGridView = PMPhotoGridView() 18 | var alwaysShowGrid: Bool = false 19 | var currentAngle = CGFloat(0) 20 | private var _editEnabled: Bool = true 21 | var editEnabled: Bool { 22 | set { 23 | _editEnabled = newValue 24 | gridMask.hidden = !newValue 25 | imageView.scrollEnabled = newValue 26 | } 27 | get { 28 | return _editEnabled 29 | } 30 | } 31 | 32 | var image: UIImage { 33 | get { 34 | if let image = imageView.imageView.image { 35 | return image 36 | } 37 | return UIImage() 38 | } 39 | } 40 | 41 | override init(frame: CGRect) { 42 | super.init(frame: frame) 43 | configSubviews() 44 | } 45 | 46 | required init?(coder aDecoder: NSCoder) { 47 | super.init(coder: aDecoder) 48 | configSubviews() 49 | } 50 | 51 | func configSubviews() { 52 | 53 | imageView.frame = bounds 54 | addSubview(imageView) 55 | 56 | // Grid 57 | gridMask.frame = bounds 58 | gridMask.alpha = alwaysShowGrid ?1:0 59 | gridMask.userInteractionEnabled = false 60 | addSubview(gridMask) 61 | imageView.addObserver(self, forKeyPath: "contentOffset", options: .New, context: &kContentOffsetContext) 62 | 63 | // Tap 64 | let tap = UITapGestureRecognizer.init(target: self, action: #selector(PMPhotoHeaderView.tap(_:))) 65 | tap.numberOfTapsRequired = 1 66 | addGestureRecognizer(tap) 67 | 68 | // Zoom action 69 | imageView.scrollViewDidZoom = { (scrollView: UIScrollView) in 70 | self.scrollViewDidZoom(scrollView) 71 | } 72 | imageView.scrollViewBeganDragging = { (scrollView: UIScrollView) in 73 | if self.alwaysShowGrid { 74 | return 75 | } 76 | self.showGrid(true) 77 | } 78 | imageView.scrollViewEndDragging = { (scrollView: UIScrollView) in 79 | if self.alwaysShowGrid { 80 | return 81 | } 82 | self.showGrid(false) 83 | } 84 | } 85 | 86 | override func layoutSubviews() { 87 | if imageView.bounds.size.width != bounds.size.width { 88 | imageView.frame = bounds 89 | gridMask.frame = bounds 90 | } 91 | if alwaysShowGrid { 92 | gridMask.alpha = 1 93 | } 94 | } 95 | 96 | func setImage(image: UIImage, scrollToRect: CGRect, zoomScale: CGFloat) { 97 | imageView.setImage(image, scrollToRect: scrollToRect, zoomScale: zoomScale) 98 | } 99 | 100 | func tap(tap: UITapGestureRecognizer) { 101 | if let tap = tapAction { 102 | tap(view: self) 103 | } 104 | } 105 | 106 | func rotate(angle: CGFloat, closeWise: Bool) { 107 | currentAngle = angle 108 | UIView.animateWithDuration(0.12, animations: { 109 | self.transform = CGAffineTransformMakeRotation(angle) 110 | }) { (com: Bool) in 111 | 112 | } 113 | } 114 | 115 | func cropImageAffterEdit() -> UIImage { 116 | // Get the rect 117 | var imageRect = CGRectZero 118 | let ratio = image.size.width/imageView.contentSize.width 119 | var x = fmax(imageView.contentOffset.x, 0) 120 | var y = fmax(imageView.contentOffset.y, 0) 121 | x = x/imageView.contentSize.width * image.size.width 122 | y = y/imageView.contentSize.height * image.size.height 123 | imageRect = CGRectMake(x, y, bounds.size.width * ratio, bounds.size.height * ratio) 124 | 125 | // Crop 126 | var croppedImage = PMImageManger.cropImageToRect(self.image, toRect: imageRect) 127 | // Rotate 128 | let imageOrientation = PMImageManger.imageOrientationFromDegress(currentAngle) 129 | if imageOrientation != .Up { 130 | croppedImage = UIImage.init(CGImage: croppedImage.CGImage!, scale: croppedImage.scale, orientation: imageOrientation) 131 | } 132 | return croppedImage 133 | } 134 | 135 | func scrollViewDidZoom(scrollView: UIScrollView) { 136 | // Reset grid 137 | let imageContainerView = imageView.imageContainerView 138 | let containerFrame = convertRect(imageContainerView.frame, fromView: imageContainerView.superview) 139 | 140 | let x = fmax(0, containerFrame.origin.x) 141 | let y = fmax(0, containerFrame.origin.y) 142 | 143 | var width = CGFloat(0) 144 | if x > 0 { 145 | width = fmin(containerFrame.size.width, bounds.size.width - x) 146 | }else { 147 | width = fmin(containerFrame.size.width + containerFrame.origin.x, bounds.size.width) 148 | } 149 | var height = CGFloat(0) 150 | if y > 0 { 151 | height = fmin(containerFrame.size.height, bounds.size.height - y) 152 | }else { 153 | height = fmin(containerFrame.size.height + containerFrame.origin.y, bounds.size.height) 154 | } 155 | 156 | gridMask.frame = CGRectMake(x, y, width, height) 157 | } 158 | 159 | func showGrid(show: Bool) { 160 | if show { 161 | UIView.animateWithDuration(0.3, animations: { 162 | self.gridMask.alpha = 1 163 | }) 164 | }else { 165 | UIView.animateWithDuration(0.35, animations: { 166 | self.gridMask.alpha = 0 167 | }) 168 | } 169 | } 170 | 171 | // MARK: KVO 172 | 173 | override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer) { 174 | if context == &kContentOffsetContext { 175 | 176 | if let scrollView = object as? UIScrollView { 177 | guard !scrollView.zooming && !scrollView.zoomBouncing else { 178 | return 179 | } 180 | 181 | let imageContainerView = imageView.imageContainerView 182 | let containerFrame = convertRect(imageContainerView.frame, fromView: imageContainerView.superview) 183 | 184 | let x = fmax(0, containerFrame.origin.x) 185 | let y = fmax(0, containerFrame.origin.y) 186 | 187 | var width = CGFloat(0) 188 | if x > 0 { 189 | width = fmin(containerFrame.size.width, bounds.size.width - x) 190 | }else { 191 | width = fmin(containerFrame.size.width + containerFrame.origin.x, bounds.size.width) 192 | } 193 | var height = CGFloat(0) 194 | if y > 0 { 195 | height = fmin(containerFrame.size.height, bounds.size.height - y) 196 | }else { 197 | height = fmin(containerFrame.size.height + containerFrame.origin.y, bounds.size.height) 198 | } 199 | 200 | gridMask.frame = CGRectMake(x, y, width, height) 201 | } 202 | }else { 203 | super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context) 204 | } 205 | } 206 | 207 | deinit { 208 | removeObserver(self, forKeyPath: "contentOffset", context: &kContentOffsetContext) 209 | } 210 | 211 | 212 | /* 213 | // Only override drawRect: if you perform custom drawing. 214 | // An empty implementation adversely affects performance during animation. 215 | override func drawRect(rect: CGRect) { 216 | // Drawing code 217 | } 218 | */ 219 | 220 | } 221 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaImagePicker/PickerView/PMPickerTitleButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMPickerTitleButton.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/7/25. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | enum ArrowStatus { 12 | case up 13 | case down 14 | } 15 | 16 | class PMPickerTitleButton: UIButton { 17 | 18 | var arrowStatus: ArrowStatus = .down 19 | 20 | override init(frame: CGRect) { 21 | super.init(frame: frame) 22 | } 23 | 24 | required init?(coder aDecoder: NSCoder) { 25 | fatalError("init(coder:) has not been implemented") 26 | } 27 | 28 | override func titleRectForContentRect(contentRect: CGRect) -> CGRect { 29 | var rect = contentRect 30 | rect.size.width -= contentRect.size.height 31 | return rect 32 | } 33 | 34 | override func imageRectForContentRect(contentRect: CGRect) -> CGRect { 35 | var rect = contentRect 36 | rect.size.width = contentRect.size.height 37 | rect.origin.x = CGRectGetWidth(contentRect) - CGRectGetWidth(rect) 38 | return rect 39 | } 40 | 41 | /* 42 | // Only override drawRect: if you perform custom drawing. 43 | // An empty implementation adversely affects performance during animation. 44 | override func drawRect(rect: CGRect) { 45 | // Drawing code 46 | } 47 | */ 48 | 49 | } 50 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaPhotoCapture/PMImageEditController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMImageEditController.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/7/24. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PMImageEditController: UIViewController { 12 | 13 | @IBOutlet weak var navigationBar: UINavigationBar! 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | navigationBar.setBackgroundImage(UIImage.init(), forBarPosition: UIBarPosition.Top, barMetrics: UIBarMetrics.Default) 19 | navigationBar.shadowImage = UIImage.init() 20 | } 21 | 22 | @IBAction func rotateRight(sender: AnyObject) { 23 | photoPisplayBoard?.rotateDisplayImage(true) 24 | } 25 | 26 | @IBAction func rotateLeft(sender: AnyObject) { 27 | photoPisplayBoard?.rotateDisplayImage(false) 28 | } 29 | 30 | @IBAction func next(sender: AnyObject) { 31 | let finalImage = photoPisplayBoard?.croppedImage() 32 | photoPisplayBoard?.setState(.SingleShow, image: finalImage, selectedRect: CGRectZero, zoomScale:1, animated: false) 33 | 34 | // Push to style vc 35 | let storyBoard = UIStoryboard.init(name: "Main", bundle: nil) 36 | let styleVC = storyBoard.instantiateViewControllerWithIdentifier("styleImageController") as? PMImageProcessController 37 | navigationController?.pushViewController(styleVC!, animated: true) 38 | } 39 | 40 | @IBAction func back(sender: AnyObject) { 41 | let navigationController = self.navigationController as? PMNavigationController 42 | navigationController?.popViewControllerAnimated(true, completion: { (isPush: Bool) in 43 | if !isPush { 44 | self.photoPisplayBoard?.setState(PMImageDisplayState.Preivew, image: nil, selectedRect: CGRectZero, zoomScale:1, animated: true) 45 | } 46 | }) 47 | } 48 | 49 | override func viewDidDisappear(animated: Bool) { 50 | super.viewDidDisappear(animated) 51 | // Pop handle 52 | if navigationController == nil { 53 | self.photoPisplayBoard?.setState(PMImageDisplayState.Preivew, image: nil, selectedRect: CGRectZero, zoomScale:1, animated: true) 54 | } 55 | } 56 | 57 | override func didReceiveMemoryWarning() { 58 | super.didReceiveMemoryWarning() 59 | // Dispose of any resources that can be recreated. 60 | } 61 | 62 | 63 | /* 64 | // MARK: - Navigation 65 | 66 | // In a storyboard-based application, you will often want to do a little preparation before navigation 67 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 68 | // Get the new view controller using segue.destinationViewController. 69 | // Pass the selected object to the new view controller. 70 | } 71 | */ 72 | 73 | } 74 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaPhotoCapture/PMImageProcessController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMImageProcessController.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/7/24. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PMImageProcessController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource { 12 | 13 | 14 | @IBOutlet weak var navigationBar: UINavigationBar! 15 | @IBOutlet weak var stylesCollectionView: UICollectionView! 16 | var styles: [AnyObject]? 17 | 18 | var fromCapture: Bool = false 19 | 20 | 21 | override func viewDidLoad() { 22 | super.viewDidLoad() 23 | 24 | navigationBar.setBackgroundImage(UIImage.init(), forBarPosition: UIBarPosition.Top, barMetrics: UIBarMetrics.Default) 25 | navigationBar.shadowImage = UIImage.init() 26 | 27 | let navigationController = self.navigationController as? PMNavigationController 28 | stylesCollectionView.panGestureRecognizer.requireGestureRecognizerToFail(navigationController!.panGestureRecognizer) 29 | 30 | styles = getStyles() as? [AnyObject] 31 | } 32 | 33 | func getStyles() -> AnyObject { 34 | let dataPath = NSBundle.mainBundle().pathForResource("", ofType: "json") 35 | let data = NSData.init(contentsOfFile: dataPath!) 36 | let dataDic: AnyObject = try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) 37 | 38 | let styles: AnyObject = dataDic.objectForKey("styles")! 39 | return styles 40 | } 41 | 42 | @IBAction func back(sender: AnyObject) { 43 | let navigationController = self.navigationController as? PMNavigationController 44 | navigationController?.popViewControllerAnimated(true, completion: { (isPush: Bool) in 45 | if !isPush { 46 | let state = self.fromCapture ?PMImageDisplayState.Preivew:PMImageDisplayState.EditImage 47 | self.photoPisplayBoard?.setState(state, image: nil, selectedRect: CGRectZero, zoomScale:1, animated: true) 48 | } 49 | }) 50 | } 51 | 52 | // MARK: UICollectionView M 53 | 54 | func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 55 | return 10 56 | } 57 | 58 | func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { 59 | let cell = collectionView.dequeueReusableCellWithReuseIdentifier("styleCell", forIndexPath: indexPath) as? PMStyleCell 60 | 61 | let style: AnyObject = styles![indexPath.row] 62 | cell?.loadImage(style) 63 | 64 | return cell! 65 | } 66 | 67 | func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { 68 | print("click item at \(indexPath.item)") 69 | } 70 | 71 | override func viewDidDisappear(animated: Bool) { 72 | super.viewDidDisappear(animated) 73 | // Pop handle 74 | if navigationController == nil { 75 | let state = fromCapture ?PMImageDisplayState.Preivew:PMImageDisplayState.EditImage 76 | self.photoPisplayBoard?.setState(state, image: nil, selectedRect: CGRectZero, zoomScale:1, animated: true) 77 | } 78 | } 79 | 80 | override func didReceiveMemoryWarning() { 81 | super.didReceiveMemoryWarning() 82 | // Dispose of any resources that can be recreated. 83 | } 84 | 85 | 86 | /* 87 | // MARK: - Navigation 88 | 89 | // In a storyboard-based application, you will often want to do a little preparation before navigation 90 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 91 | // Get the new view controller using segue.destinationViewController. 92 | // Pass the selected object to the new view controller. 93 | } 94 | */ 95 | 96 | } 97 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaPhotoCapture/PMImageProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMImageProtocol.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/7/29. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AVFoundation 11 | 12 | @objc enum PMImageOrientation : Int { 13 | case Up // Normal affter rotated 14 | case Down // Down affter rotated 15 | case Left // Left affter rotated 16 | case Right // Right after rotated 17 | } 18 | 19 | @objc enum PMImageDisplayState : Int { 20 | case Preivew // Display AVCapturePreviewLayer 21 | case EditImage // Edit image, such as rotate, scale. 22 | case SingleShow // Just display image to make art photo 23 | } 24 | 25 | @objc protocol PMImageProtocol { 26 | // Display image 27 | optional var displayImage: UIImage { get } 28 | 29 | // Display header view 30 | var displayHeaderView: UIView { get } 31 | 32 | // Image orienttation affter rotated 33 | var rotatedImageOrientation: PMImageOrientation { get } 34 | 35 | // Tap header to focus 36 | var singleTapHeaderAction: ((tap: UITapGestureRecognizer)->Void) { get set } 37 | 38 | // Set the AVCaptureVideoPreviewLayer 39 | func setAVCapturePreviewLayer(layer: AVCaptureVideoPreviewLayer) 40 | 41 | // Change state 42 | func setState(state: PMImageDisplayState, image: UIImage?, selectedRect: CGRect, zoomScale:CGFloat, animated: Bool) 43 | 44 | // Rotate image 45 | func rotateDisplayImage(clockwise: Bool) 46 | 47 | // Cropped image affter edit 48 | func croppedImage() -> UIImage 49 | 50 | } 51 | 52 | extension UIViewController { 53 | var photoPisplayBoard: PMImageProtocol? { 54 | get { 55 | let vc = UIApplication.sharedApplication().keyWindow?.rootViewController 56 | if let rootVC = vc as? PMRootViewController { 57 | return rootVC 58 | } 59 | return nil 60 | } 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaPhotoCapture/PMImageSettingController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMImageSettingController.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/8/2. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PMImageSettingController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | // Do any additional setup after loading the view. 17 | } 18 | 19 | override func didReceiveMemoryWarning() { 20 | super.didReceiveMemoryWarning() 21 | // Dispose of any resources that can be recreated. 22 | } 23 | 24 | 25 | /* 26 | // MARK: - Navigation 27 | 28 | // In a storyboard-based application, you will often want to do a little preparation before navigation 29 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 30 | // Get the new view controller using segue.destinationViewController. 31 | // Pass the selected object to the new view controller. 32 | } 33 | */ 34 | 35 | } 36 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaPhotoCapture/PMImageSettingController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaPhotoCapture/PMNavigationController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMNavigationController.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/7/24. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | let kPushDuration = 0.32 12 | 13 | class PushAnimator: NSObject, UIViewControllerAnimatedTransitioning { 14 | 15 | var push: Bool = true 16 | var isInteractive: Bool = false 17 | 18 | 19 | override init() { 20 | super.init() 21 | } 22 | 23 | convenience init(isPush: Bool) { 24 | self.init() 25 | self.push = isPush 26 | } 27 | 28 | func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { 29 | return kPushDuration 30 | } 31 | 32 | func animateTransition(transitionContext: UIViewControllerContextTransitioning) { 33 | 34 | let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) 35 | let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) 36 | let containerView = transitionContext.containerView() 37 | 38 | containerView.addSubview(fromViewController!.view) 39 | containerView.addSubview(toViewController!.view) 40 | toViewController?.view.frame = fromViewController!.view.bounds 41 | 42 | var fromFrame = fromViewController?.view.frame 43 | var toFrame = toViewController?.view.frame 44 | let screenWidth = UIScreen.mainScreen().bounds.size.width 45 | var animationOption = UIViewAnimationOptions.CurveEaseInOut 46 | 47 | if isInteractive { 48 | animationOption = UIViewAnimationOptions.CurveLinear 49 | } 50 | 51 | if push { 52 | toFrame?.origin.x = screenWidth 53 | toViewController?.view.frame = toFrame! 54 | UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0, options: animationOption, animations: { 55 | fromFrame?.origin.x = -screenWidth 56 | fromViewController?.view.frame = fromFrame! 57 | toFrame?.origin.x = 0 58 | toViewController?.view.frame = toFrame! 59 | }, completion: { (com: Bool) in 60 | let complete = !transitionContext.transitionWasCancelled() 61 | if complete { 62 | if let nav = fromViewController?.navigationController as? PMNavigationController { 63 | if let completion = nav.completionHandler { 64 | completion(isPush: true) 65 | } 66 | } 67 | } 68 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled()) 69 | }) 70 | }else { 71 | toFrame?.origin.x = -screenWidth 72 | toViewController?.view.frame = toFrame! 73 | UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0, options: animationOption, animations: { 74 | fromFrame?.origin.x = screenWidth 75 | fromViewController?.view.frame = fromFrame! 76 | toFrame?.origin.x = 0 77 | toViewController?.view.frame = toFrame! 78 | }, completion: { (com: Bool) in 79 | let complete = !transitionContext.transitionWasCancelled() 80 | if complete { 81 | if let nav = toViewController?.navigationController as? PMNavigationController { 82 | if let completion = nav.completionHandler { 83 | completion(isPush: false) 84 | } 85 | } 86 | } 87 | transitionContext.completeTransition(complete) 88 | }) 89 | } 90 | 91 | } 92 | } 93 | 94 | 95 | 96 | class PMNavigationController: UINavigationController, UIGestureRecognizerDelegate, UINavigationControllerDelegate { 97 | 98 | var panGestureRecognizer: UIPanGestureRecognizer = UIPanGestureRecognizer.init() 99 | var frameOrigin: CGPoint = CGPointZero 100 | var interactionController: UIPercentDrivenInteractiveTransition? 101 | var animator: PushAnimator? 102 | var isInteractive: Bool = false 103 | var popEdgeInset: CGFloat = 50 104 | var completionHandler: ((isPush: Bool)->Void)? 105 | 106 | 107 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { 108 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 109 | } 110 | 111 | override init(rootViewController: UIViewController) { 112 | super.init(rootViewController: rootViewController) 113 | } 114 | 115 | required init?(coder aDecoder: NSCoder) { 116 | super.init(coder: aDecoder) 117 | } 118 | 119 | override func viewDidLoad() { 120 | super.viewDidLoad() 121 | 122 | interactivePopGestureRecognizer?.enabled = false 123 | delegate = self 124 | 125 | // Add new pan gesture replace the edge gesture 126 | panGestureRecognizer.addTarget(self, action: #selector(PMNavigationController.didPan(_:))) 127 | panGestureRecognizer.delegate = self 128 | view.addGestureRecognizer(panGestureRecognizer) 129 | } 130 | 131 | // MARK: Change the frame of the default view, under the capture view 132 | override func viewDidLayoutSubviews() { 133 | var frame = view.frame 134 | frame.origin.y = frameOrigin.y 135 | frame.size.height = UIScreen.mainScreen().bounds.size.height - frame.origin.y 136 | view.frame = frame 137 | } 138 | 139 | override func pushViewController(viewController: UIViewController, animated: Bool) { 140 | super.pushViewController(viewController, animated: animated) 141 | if !animated { 142 | if let completion = completionHandler { 143 | completion(isPush: true) 144 | } 145 | } 146 | } 147 | 148 | override func popViewControllerAnimated(animated: Bool) -> UIViewController? { 149 | if !animated { 150 | if let completion = completionHandler { 151 | completion(isPush: false) 152 | } 153 | } 154 | return super.popViewControllerAnimated(animated) 155 | } 156 | 157 | func pushViewController(viewController: UIViewController, animated: Bool, completion:((isPush: Bool)->Void)?) { 158 | completionHandler = completion 159 | self.pushViewController(viewController, animated: animated) 160 | } 161 | 162 | 163 | func popViewControllerAnimated(animated: Bool, completion:((isPush: Bool)->Void)?) -> UIViewController? { 164 | completionHandler = completion 165 | return self.popViewControllerAnimated(animated) 166 | } 167 | 168 | // MARK: Transition animation 169 | 170 | func navigationController(navigationController: UINavigationController, animationControllerForOperation operation: UINavigationControllerOperation, fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { 171 | if animator == nil { 172 | animator = PushAnimator.init(isPush: operation == UINavigationControllerOperation.Push) 173 | } 174 | animator?.isInteractive = isInteractive 175 | animator?.push = operation == UINavigationControllerOperation.Push 176 | return animator! 177 | } 178 | 179 | func navigationController(navigationController: UINavigationController, interactionControllerForAnimationController animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { 180 | return interactionController 181 | } 182 | 183 | func didPan(panGestureRecognizer: UIPanGestureRecognizer) { 184 | 185 | if panGestureRecognizer.state == .Began { 186 | 187 | isInteractive = true 188 | animator?.isInteractive = true 189 | interactionController = UIPercentDrivenInteractiveTransition() 190 | popViewControllerAnimated(true) 191 | }else if panGestureRecognizer.state == .Changed { 192 | 193 | let translaton = panGestureRecognizer.translationInView(view) 194 | let percent = translaton.x / CGRectGetWidth(view!.bounds) 195 | interactionController!.updateInteractiveTransition(percent) 196 | }else if panGestureRecognizer.state == .Ended { 197 | 198 | if panGestureRecognizer.velocityInView(view).x > 100 { 199 | interactionController!.finishInteractiveTransition() 200 | }else { 201 | interactionController!.cancelInteractiveTransition() 202 | } 203 | interactionController = nil 204 | animator?.isInteractive = false 205 | } 206 | } 207 | 208 | // MARK: UIGestureRecognizerDelegate 209 | 210 | func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool { 211 | let location = gestureRecognizer.locationInView(view) 212 | if location.y < 64 || location.x > popEdgeInset { 213 | return false 214 | } 215 | return true 216 | } 217 | 218 | override func didReceiveMemoryWarning() { 219 | super.didReceiveMemoryWarning() 220 | // Dispose of any resources that can be recreated. 221 | } 222 | 223 | 224 | /* 225 | // MARK: - Navigation 226 | 227 | // In a storyboard-based application, you will often want to do a little preparation before navigation 228 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 229 | // Get the new view controller using segue.destinationViewController. 230 | // Pass the selected object to the new view controller. 231 | } 232 | */ 233 | 234 | } 235 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaPhotoCapture/PMRootViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMRootViewController.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/7/24. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AVFoundation 11 | 12 | class PMRootViewController: UIViewController, PMImageProtocol { 13 | 14 | 15 | @IBOutlet weak var captureHeaderView: UIView! 16 | var previewLayer: AVCaptureVideoPreviewLayer? 17 | var photoHeaderView: PMPhotoHeaderView? 18 | var styleHeaderView: PMStyleHeaderView? 19 | var state: PMImageDisplayState = PMImageDisplayState.Preivew 20 | var imageAngle: CGFloat = 0 21 | 22 | 23 | override func viewDidLoad() { 24 | super.viewDidLoad() 25 | 26 | captureHeaderView.backgroundColor = UIColor.blackColor() 27 | captureHeaderView.layer.masksToBounds = true 28 | 29 | // Add navigation 30 | let storyBoard = UIStoryboard.init(name: "Main", bundle: nil) 31 | let baseNav = storyBoard.instantiateViewControllerWithIdentifier("mainNavigationController") as? PMNavigationController 32 | baseNav!.frameOrigin = CGPointMake(0, UIScreen.mainScreen().bounds.size.width) 33 | self.addChildViewController(baseNav!) 34 | view.addSubview(baseNav!.view) 35 | 36 | // Tap gesture to focus 37 | let tap = UITapGestureRecognizer.init(target: self, action: #selector(PMRootViewController.tapHeader)) 38 | tap.numberOfTapsRequired = 1 39 | captureHeaderView.addGestureRecognizer(tap) 40 | } 41 | 42 | override func viewDidAppear(animated: Bool) { 43 | // Preview 44 | if let layer = previewLayer { 45 | CATransaction.begin() 46 | CATransaction.setDisableActions(true) 47 | layer.frame = captureHeaderView.bounds 48 | CATransaction.commit() 49 | } 50 | } 51 | 52 | // Tap header to focus 53 | func tapHeader(tap: UITapGestureRecognizer) { 54 | guard state == .Preivew else { 55 | return 56 | } 57 | singleTapHeaderAction(tap: tap) 58 | } 59 | 60 | 61 | // MARK: PMImageProtocol 62 | 63 | // Display header view 64 | var displayHeaderView: UIView { 65 | return captureHeaderView 66 | } 67 | 68 | // Display image 69 | var displayImage: UIImage { 70 | get { 71 | if let style = styleHeaderView { 72 | return style.imageView.image! 73 | } 74 | return (photoHeaderView?.image)! 75 | } 76 | } 77 | 78 | // Tap header to focus 79 | private var _singleTapHeaderAction: ((tap: UITapGestureRecognizer)->Void) = {(tap: UITapGestureRecognizer) in} 80 | var singleTapHeaderAction: ((tap: UITapGestureRecognizer)->Void) { 81 | set { 82 | _singleTapHeaderAction = newValue 83 | } 84 | get { 85 | return _singleTapHeaderAction 86 | } 87 | } 88 | 89 | // Image orienttation affter rotated 90 | private var _rotatedImageOrientation: PMImageOrientation = .Up 91 | var rotatedImageOrientation: PMImageOrientation { 92 | get { 93 | return _rotatedImageOrientation 94 | } 95 | set { 96 | _rotatedImageOrientation = newValue 97 | } 98 | } 99 | 100 | // Set the AVCaptureVideoPreviewLayer 101 | func setAVCapturePreviewLayer(previewLayer: AVCaptureVideoPreviewLayer) { 102 | self.previewLayer = previewLayer 103 | captureHeaderView.layer.insertSublayer(previewLayer, atIndex: 0) 104 | } 105 | 106 | // Change state 107 | func setState(state: PMImageDisplayState, image: UIImage?, selectedRect: CGRect, zoomScale:CGFloat, animated: Bool) { 108 | guard self.state != state else { 109 | return 110 | } 111 | let duration = animated ?0.25:0.0 112 | switch state { 113 | case .Preivew: 114 | captureHeaderView.backgroundColor = UIColor.blackColor() 115 | 116 | // Reset the angle 117 | imageAngle = 0 118 | // Hidden other header 119 | UIView.animateWithDuration(0.25, animations: { 120 | if let editHeader = self.photoHeaderView { 121 | editHeader.alpha = 0 122 | } 123 | if let styleHeader = self.styleHeaderView { 124 | styleHeader.alpha = 0 125 | } 126 | self.previewLayer?.opacity = 1 127 | }, completion: { (com: Bool) in 128 | if com { 129 | self.photoHeaderView?.removeFromSuperview() 130 | self.photoHeaderView = nil 131 | self.styleHeaderView?.removeFromSuperview() 132 | self.styleHeaderView = nil 133 | } 134 | }) 135 | break 136 | case .EditImage: 137 | captureHeaderView.backgroundColor = UIColor.whiteColor() 138 | 139 | if self.state == .Preivew { 140 | // Go edit vc and add edit header 141 | let photoHeaderView = PMPhotoHeaderView.init(frame: captureHeaderView.bounds) 142 | photoHeaderView.backgroundColor = UIColor.whiteColor() 143 | photoHeaderView.alpha = 0 144 | photoHeaderView.alwaysShowGrid = true 145 | captureHeaderView.addSubview(photoHeaderView) 146 | // config the image rect 147 | var toRect = selectedRect 148 | if zoomScale == 1 { 149 | toRect.origin.x = toRect.origin.x * (photoHeaderView.imageView.contentSize.width/(image?.size.width)!) 150 | toRect.origin.y = toRect.origin.y * (photoHeaderView.imageView.contentSize.height/(image?.size.height)!) 151 | } 152 | 153 | toRect.size = photoHeaderView.bounds.size 154 | photoHeaderView.setImage(image!, scrollToRect: toRect, zoomScale:zoomScale) 155 | 156 | UIView.animateWithDuration(duration, animations: { 157 | photoHeaderView.alpha = 1 158 | self.previewLayer?.opacity = 0 159 | }, completion: { (com: Bool) in 160 | 161 | }) 162 | self.photoHeaderView = photoHeaderView 163 | }else if self.state == .SingleShow { 164 | UIView.animateWithDuration(duration, animations: { 165 | self.styleHeaderView?.alpha = 0 166 | }, completion: { (com: Bool) in 167 | self.styleHeaderView?.removeFromSuperview() 168 | self.styleHeaderView = nil 169 | }) 170 | } 171 | break 172 | case .SingleShow: 173 | // Go style vc 174 | let styleHeaderView = PMStyleHeaderView.init(frame: captureHeaderView.bounds) 175 | styleHeaderView.setImage(image!) 176 | styleHeaderView.alpha = 0 177 | captureHeaderView.addSubview(styleHeaderView) 178 | 179 | UIView.animateWithDuration(duration, animations: { 180 | styleHeaderView.alpha = 1 181 | self.previewLayer?.opacity = 0 182 | }, completion: { (com: Bool) in 183 | 184 | }) 185 | self.styleHeaderView = styleHeaderView 186 | 187 | break 188 | } 189 | self.state = state 190 | } 191 | 192 | // Rotate image 193 | func rotateDisplayImage(clockwise: Bool) { 194 | 195 | if clockwise { 196 | imageAngle += CGFloat(M_PI/2) 197 | }else { 198 | imageAngle -= CGFloat(M_PI/2) 199 | } 200 | photoHeaderView?.rotate(imageAngle, closeWise: clockwise) 201 | } 202 | 203 | // Cropped image affter edit 204 | func croppedImage() -> UIImage { 205 | let image = photoHeaderView?.cropImageAffterEdit() 206 | return image! 207 | } 208 | 209 | override func prefersStatusBarHidden() -> Bool { 210 | return true 211 | } 212 | 213 | override func didReceiveMemoryWarning() { 214 | super.didReceiveMemoryWarning() 215 | // Dispose of any resources that can be recreated. 216 | } 217 | 218 | 219 | /* 220 | // MARK: - Navigation 221 | 222 | // In a storyboard-based application, you will often want to do a little preparation before navigation 223 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 224 | // Get the new view controller using segue.destinationViewController. 225 | // Pass the selected object to the new view controller. 226 | } 227 | */ 228 | 229 | } 230 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaPhotoCapture/PNImageCaptureController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PNImageCaptureController.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/7/24. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AVFoundation 11 | import AssetsLibrary 12 | import Photos 13 | import CoreImage 14 | 15 | class PNImageCaptureController: UIViewController, PMImagePickerControllerDelegate { 16 | 17 | 18 | @IBOutlet weak var captureButton: PMCaptureButton! 19 | @IBOutlet weak var navigationBar: UINavigationBar! 20 | @IBOutlet weak var flashBarItem: UIBarButtonItem! 21 | @IBOutlet weak var selectPhotoButton: UIButton! 22 | var session: AVCaptureSession! = AVCaptureSession() 23 | var deviceIntput: AVCaptureDeviceInput? 24 | var stillImageOutPut: AVCaptureStillImageOutput? 25 | var previewLayer: AVCaptureVideoPreviewLayer? 26 | var photoGroups = [PHAssetCollection]() 27 | var photoAssets = [PHAsset]() 28 | var isUsingFrontFacingCamera: Bool = false 29 | var currentFlashMode: AVCaptureFlashMode = .Off 30 | let screenSize = ScreenSize() 31 | let orientationManger: PMDeviceOrientation = PMDeviceOrientation() 32 | 33 | 34 | override func viewDidLoad() { 35 | super.viewDidLoad() 36 | 37 | // Init view 38 | initNavigationBar() 39 | 40 | // Auth 41 | PMImageManger.captureAuthorization { (canCapture: Bool) in 42 | if canCapture { 43 | self.initAVCapture() 44 | self.session.startRunning() 45 | }else { 46 | self.session.stopRunning() 47 | } 48 | } 49 | 50 | PMImageManger.photoAuthorization { (canAssets: Bool) in 51 | if canAssets { 52 | self.photoGroups = PMImageManger.photoLibrarys() 53 | self.photoAssets = PMImageManger.photoAssetsForAlbum(self.photoGroups.first!) 54 | PMImageManger.imageFromAsset(self.photoAssets.first!, isOriginal: false, toSize: CGSizeMake(150, 150), resultHandler: { (image: UIImage?) in 55 | self.selectPhotoButton.setBackgroundImage(image, forState: .Normal) 56 | }) 57 | } 58 | } 59 | 60 | // Tap header to change focus 61 | photoPisplayBoard?.singleTapHeaderAction = { (tap: UITapGestureRecognizer) in 62 | self.tapToChangeFocus(tap) 63 | } 64 | } 65 | 66 | func initNavigationBar() { 67 | // Navigation bar 68 | navigationBar.setBackgroundImage(UIImage.init(), forBarPosition: UIBarPosition.Top, barMetrics: UIBarMetrics.Default) 69 | navigationBar.shadowImage = UIImage.init() 70 | 71 | let navigationItem = navigationBar.topItem 72 | 73 | // Flash button 74 | let letButton = UIButton.init(type: UIButtonType.System) 75 | letButton.frame = CGRectMake(-10, 0, 44, 44) 76 | letButton.setImage(UIImage.init(named: "flash"), forState: UIControlState.Normal) 77 | letButton.addTarget(self, action: #selector(self.changeFlash(_:)), forControlEvents: UIControlEvents.TouchUpInside) 78 | let letBarItem = UIBarButtonItem.init(customView: letButton) 79 | letButton.imageEdgeInsets = UIEdgeInsetsMake(0, -10, 0, 10) 80 | navigationItem!.leftBarButtonItem = letBarItem 81 | 82 | // Camera possion 83 | let image = UIImage.init(named: "flip") 84 | let hImage = image?.imageWithColor(UIColor.lightGrayColor()) 85 | let titleButton = UIButton.init(type: UIButtonType.Custom) 86 | titleButton.setImage(image, forState: UIControlState.Normal) 87 | titleButton.setImage(hImage, forState: UIControlState.Selected) 88 | titleButton.setImage(hImage, forState: UIControlState.Highlighted) 89 | titleButton.sizeToFit() 90 | titleButton.addTarget(self, action: #selector(self.changeCameraPossion), forControlEvents: UIControlEvents.TouchUpInside) 91 | navigationItem!.titleView = titleButton 92 | } 93 | 94 | func initAVCapture() { 95 | // Device 96 | let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) 97 | 98 | try! device.lockForConfiguration() 99 | if device.hasFlash { 100 | device.flashMode = AVCaptureFlashMode.Off 101 | } 102 | if device.isFocusModeSupported(.AutoFocus) { 103 | device.focusMode = .AutoFocus 104 | } 105 | if device.isWhiteBalanceModeSupported(.AutoWhiteBalance) { 106 | device.whiteBalanceMode = .AutoWhiteBalance 107 | } 108 | if device.exposurePointOfInterestSupported { 109 | device.exposureMode = .ContinuousAutoExposure 110 | } 111 | device.unlockForConfiguration() 112 | 113 | // Input & Output 114 | // When init AVCaptureDeviceInput first, system will show alert to confirm the authentication from user. 115 | // But the best way is send the acces request manual. see `requestAccessForMediaType` 116 | deviceIntput = try! AVCaptureDeviceInput(device: device) 117 | stillImageOutPut = AVCaptureStillImageOutput() 118 | 119 | // Output settings 120 | stillImageOutPut?.outputSettings = [AVVideoCodecKey:AVVideoCodecJPEG, AVVideoScalingModeKey:AVVideoScalingModeResize] 121 | 122 | if session.canAddInput(deviceIntput) { 123 | session.addInput(deviceIntput) 124 | } 125 | if session.canAddOutput(stillImageOutPut) { 126 | session.addOutput(stillImageOutPut) 127 | } 128 | 129 | session.sessionPreset = AVCaptureSessionPresetPhoto 130 | // Preview 131 | previewLayer = AVCaptureVideoPreviewLayer.init(session: session) 132 | previewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill 133 | 134 | // Set root vc avcapture preview layer 135 | photoPisplayBoard?.setAVCapturePreviewLayer(previewLayer!) 136 | } 137 | 138 | // MARK: Capture action 139 | 140 | @IBAction func capturePhoto(sender: AnyObject) { 141 | 142 | // Disable the capture button 143 | captureButton.enabled = false 144 | 145 | let stillImageConnection = stillImageOutPut?.connectionWithMediaType(AVMediaTypeVideo) 146 | // let curDeviceOrientation = UIDevice.currentDevice().orientation 147 | // let avCaptureOrientation = PMDeviceOrientation.avOrientationFromDeviceOrientation(curDeviceOrientation) 148 | let avCaptureOrientation = AVCaptureVideoOrientation(rawValue: UIDevice.currentDevice().orientation.rawValue)! 149 | if stillImageConnection!.supportsVideoOrientation { 150 | stillImageConnection!.videoOrientation = avCaptureOrientation 151 | } 152 | stillImageConnection!.videoScaleAndCropFactor = 1 153 | 154 | stillImageOutPut?.captureStillImageAsynchronouslyFromConnection(stillImageConnection, completionHandler: { (imageDataSampleBuffer: CMSampleBufferRef!, error: NSError!) in 155 | let jpegData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer) 156 | 157 | if var image = UIImage(data: jpegData) { 158 | 159 | // Fix orientation & crop image 160 | image = image.fixOrientation() 161 | image = PMImageManger.cropImageAffterCapture(image,toSize: self.previewLayer!.frame.size) 162 | 163 | // Fix interface orientation 164 | if !self.orientationManger.deviceOrientationMatchesInterfaceOrientation() { 165 | let interfaceOrientation = self.orientationManger.orientation() 166 | image = image.rotateImageFromInterfaceOrientation(interfaceOrientation) 167 | } 168 | 169 | // Mirror the image 170 | if self.isUsingFrontFacingCamera { 171 | image = UIImage.init(CGImage: image.CGImage!, scale: image.scale, orientation: UIImageOrientation.UpMirrored) 172 | } 173 | 174 | // Save photo 175 | let authorStatus = ALAssetsLibrary.authorizationStatus() 176 | if authorStatus == ALAuthorizationStatus.Restricted || authorStatus == ALAuthorizationStatus.Denied { 177 | return 178 | } 179 | 180 | let library = ALAssetsLibrary() 181 | if self.isUsingFrontFacingCamera { 182 | library.writeImageToSavedPhotosAlbum(image.CGImage, orientation: ALAssetOrientation.UpMirrored, completionBlock: { (url: NSURL!, error: NSError!) in 183 | 184 | }) 185 | }else { 186 | let attachments = CMCopyDictionaryOfAttachments(kCFAllocatorDefault,imageDataSampleBuffer,kCMAttachmentMode_ShouldPropagate) 187 | // let attachments = CMGetAttachment(imageDataSampleBuffer, kCGImagePropertyExifDictionary, nil) 188 | library.writeImageToSavedPhotosAlbum(image.CGImage!, metadata: attachments as? [NSObject:AnyObject] , completionBlock: { (url: NSURL!, error: NSError!) in 189 | 190 | }) 191 | } 192 | 193 | // Go to style vc 194 | self.photoPisplayBoard?.setState(.SingleShow, image: image, selectedRect: CGRectZero, zoomScale:1, animated: false) 195 | let storyBoard = UIStoryboard.init(name: "Main", bundle: nil) 196 | let styleVC = storyBoard.instantiateViewControllerWithIdentifier("styleImageController") as? PMImageProcessController 197 | styleVC?.fromCapture = true 198 | self.navigationController?.pushViewController(styleVC!, animated: true) 199 | } 200 | 201 | // Stop session 202 | self.session.stopRunning() 203 | }) 204 | } 205 | 206 | func changeCameraPossion() { 207 | 208 | var desiredPosition : AVCaptureDevicePosition? 209 | let navigationItem = navigationBar.topItem 210 | 211 | if (isUsingFrontFacingCamera){ 212 | desiredPosition = AVCaptureDevicePosition.Back 213 | navigationItem!.leftBarButtonItem!.customView?.userInteractionEnabled = true 214 | navigationItem!.leftBarButtonItem!.highlighted = false 215 | }else{ 216 | desiredPosition = AVCaptureDevicePosition.Front 217 | navigationItem!.leftBarButtonItem!.customView?.userInteractionEnabled = false 218 | navigationItem!.leftBarButtonItem!.highlighted = true 219 | } 220 | 221 | for device in AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo) { 222 | let device = device as! AVCaptureDevice 223 | if device.position == desiredPosition { 224 | // Config device 225 | try! device.lockForConfiguration() 226 | if device.hasFlash { 227 | device.flashMode = currentFlashMode 228 | } 229 | if device.isFocusModeSupported(.AutoFocus) { 230 | device.focusMode = .ContinuousAutoFocus 231 | } 232 | if device.isWhiteBalanceModeSupported(.AutoWhiteBalance) { 233 | device.whiteBalanceMode = .AutoWhiteBalance 234 | } 235 | if device.exposurePointOfInterestSupported { 236 | device.exposureMode = .ContinuousAutoExposure 237 | } 238 | device.unlockForConfiguration() 239 | // Add device 240 | let input = try! AVCaptureDeviceInput(device: device) 241 | session.removeInput(deviceIntput) 242 | session.addInput(input) 243 | deviceIntput = input 244 | break; 245 | } 246 | } 247 | 248 | isUsingFrontFacingCamera = !isUsingFrontFacingCamera; 249 | } 250 | 251 | // Tap header to focus 252 | func tapToChangeFocus(tap: UITapGestureRecognizer) { 253 | guard !isUsingFrontFacingCamera else { 254 | return 255 | } 256 | // Location 257 | let point = tap.locationInView(photoPisplayBoard?.displayHeaderView) 258 | 259 | // Show square 260 | showSquareBox(point) 261 | 262 | // Change focus 263 | // let pointInCamera = convertToPointOfInterestFromViewCoordinates(point) 264 | let pointInCamera = previewLayer!.captureDevicePointOfInterestForPoint(point) 265 | let device = deviceIntput?.device 266 | try! device!.lockForConfiguration() 267 | 268 | if device!.focusPointOfInterestSupported { 269 | device!.focusPointOfInterest = pointInCamera 270 | } 271 | if device!.isFocusModeSupported(.ContinuousAutoFocus) { 272 | device!.focusMode = .ContinuousAutoFocus 273 | } 274 | if device!.exposurePointOfInterestSupported { 275 | device?.exposureMode = .ContinuousAutoExposure 276 | device?.exposurePointOfInterest = pointInCamera 277 | } 278 | device?.subjectAreaChangeMonitoringEnabled = true 279 | device!.focusPointOfInterest = pointInCamera 280 | 281 | device!.unlockForConfiguration() 282 | } 283 | 284 | @IBAction func selectPhoto(sender: AnyObject) { 285 | let nav = PMImagePickerController.init() 286 | nav.pmDelegate = self 287 | nav.photoGroups = photoGroups 288 | nav.photoAssets = photoAssets 289 | weak var weakSelf = self 290 | self.presentViewController(nav, animated: true) { 291 | weakSelf!.session.stopRunning() 292 | } 293 | } 294 | 295 | @IBAction func changeFlash(sender: AnyObject) { 296 | var image: UIImage? = nil 297 | 298 | let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) 299 | try! device.lockForConfiguration() 300 | if device.hasFlash { 301 | switch device.flashMode { 302 | case .Off: 303 | device.flashMode = .On 304 | currentFlashMode = .On 305 | image = UIImage.init(named: "flash-on") 306 | break 307 | case .On: 308 | device.flashMode = .Auto 309 | currentFlashMode = .Auto 310 | image = UIImage.init(named: "flash-auto") 311 | break 312 | case .Auto: 313 | device.flashMode = .Off 314 | currentFlashMode = .Off 315 | image = UIImage.init(named: "flash") 316 | break 317 | } 318 | // Flash baritem 319 | let letButton = navigationBar.topItem!.leftBarButtonItem?.customView as? UIButton 320 | letButton?.setImage(image, forState: UIControlState.Normal) 321 | } 322 | device.unlockForConfiguration() 323 | } 324 | 325 | @IBAction func setting(sender: AnyObject) { 326 | 327 | } 328 | 329 | // Show focus square box 330 | private func showSquareBox(point: CGPoint) { 331 | // remove box 332 | guard let header = photoPisplayBoard?.displayHeaderView else { 333 | return 334 | } 335 | for layer in header.layer.sublayers!{ 336 | if layer.name == "box" { 337 | layer.removeFromSuperlayer() 338 | } 339 | } 340 | // create a box layer 341 | let width = CGFloat(60) 342 | let box = CAShapeLayer.init() 343 | box.frame = CGRectMake(point.x - width/2, point.y - width/2, width, width) 344 | box.borderWidth = 1 345 | box.borderColor = UIColor.whiteColor().CGColor 346 | box.name = "box" 347 | header.layer.addSublayer(box) 348 | 349 | // animation 350 | let alphaAnimation = CABasicAnimation.init(keyPath: "opacity") 351 | alphaAnimation.fromValue = 1 352 | alphaAnimation.toValue = 0 353 | alphaAnimation.duration = 0.01 354 | alphaAnimation.beginTime = CACurrentMediaTime() 355 | 356 | let scaleAnimation = CABasicAnimation.init(keyPath: "transform.scale") 357 | scaleAnimation.fromValue = 1.2 358 | scaleAnimation.toValue = 1 359 | scaleAnimation.duration = 0.35 360 | scaleAnimation.beginTime = CACurrentMediaTime() 361 | 362 | box.addAnimation(alphaAnimation, forKey: nil) 363 | box.addAnimation(scaleAnimation, forKey: nil) 364 | 365 | let time = dispatch_time(DISPATCH_TIME_NOW, Int64((0.35 + 0.2) * Double(NSEC_PER_SEC))) 366 | dispatch_after(time, dispatch_get_main_queue()) { 367 | box.removeFromSuperlayer() 368 | } 369 | } 370 | 371 | // Convert the touch point to focus point of interest. The focus point of interest is from [0, 0] to [1, 1]. 372 | private func convertToPointOfInterestFromViewCoordinates(point: CGPoint) -> CGPoint { 373 | var interestPoint = CGPointMake(0.5, 0.5) 374 | for _port in deviceIntput!.ports { 375 | if let port = _port as? AVCaptureInputPort { 376 | let cleanAperture = CMVideoFormatDescriptionGetCleanAperture(port.formatDescription, true) 377 | let apertureSize = cleanAperture.size 378 | let frameSize = previewLayer?.bounds.size 379 | let apertureRatio = apertureSize.height / apertureSize.width; 380 | let viewRatio = frameSize!.width / frameSize!.height; 381 | var xc = CGFloat(0.5) 382 | var yc = CGFloat(0.5) 383 | 384 | // Just calculate videoGravity of AVLayerVideoGravityResizeAspectFill mode 385 | if viewRatio > apertureRatio { 386 | let y2 = apertureSize.width * (frameSize!.width / apertureSize.height) 387 | xc = (point.y + ((y2 - frameSize!.height) / 2)) / y2 388 | yc = (frameSize!.width - point.x) / frameSize!.width 389 | } else { 390 | let x2 = apertureSize.height * (frameSize!.height / apertureSize.width) 391 | yc = 1.0 - ((point.x + ((x2 - frameSize!.width) / 2)) / x2) 392 | xc = point.y / frameSize!.height 393 | } 394 | interestPoint = CGPointMake(xc, yc) 395 | break 396 | } 397 | } 398 | return interestPoint 399 | } 400 | 401 | // MARK: PMImagePickerControllerDelegate 402 | 403 | func imagePickerController(picker: PMImagePickerController, didFinishPickingImage originalImage: UIImage, selectedRect: CGRect, zoomScale:CGFloat) { 404 | photoPisplayBoard?.setState(PMImageDisplayState.EditImage, image: originalImage, selectedRect: selectedRect, zoomScale:zoomScale, animated: false) 405 | 406 | let storyBoard = UIStoryboard.init(name: "Main", bundle: nil) 407 | let editVC = storyBoard.instantiateViewControllerWithIdentifier("imageEditController") as? PMImageEditController 408 | navigationController?.pushViewController(editVC!, animated: false) 409 | } 410 | 411 | func imagePickerController(picker: PMImagePickerController, didFinishPickingImage image: UIImage) {} 412 | 413 | func imagePickerControllerDidCancel(picker: PMImagePickerController) { 414 | session.startRunning() 415 | } 416 | 417 | override func viewWillAppear(animated: Bool) { 418 | session.startRunning() 419 | captureButton.enabled = true 420 | } 421 | 422 | override func didReceiveMemoryWarning() { 423 | super.didReceiveMemoryWarning() 424 | // Dispose of any resources that can be recreated. 425 | } 426 | 427 | 428 | /* 429 | // MARK: - Navigation 430 | 431 | // In a storyboard-based application, you will often want to do a little preparation before navigation 432 | override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 433 | // Get the new view controller using segue.destinationViewController. 434 | // Pass the selected object to the new view controller. 435 | } 436 | */ 437 | 438 | } 439 | 440 | extension UIBarButtonItem { 441 | 442 | var highlighted: Bool { 443 | set { 444 | if let button = customView as? UIButton { 445 | button.highlighted = newValue 446 | } 447 | } 448 | get { 449 | if let button = customView as? UIButton { 450 | return button.highlighted 451 | } 452 | return false 453 | } 454 | } 455 | } 456 | 457 | 458 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaViews/PMCaptureButtom.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMCaptureButtom.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/7/28. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | let touchUpDuration = 0.4 12 | 13 | class PMTarget: NSObject { 14 | var target: AnyObject? 15 | var action: Selector? 16 | var touchAction: Selector = #selector(PMTarget.touch(_:)) 17 | 18 | override init() { 19 | super.init() 20 | } 21 | 22 | convenience init(target: AnyObject, action: Selector) { 23 | self.init() 24 | self.target = target 25 | self.action = action 26 | } 27 | 28 | func touch(sender: UIButton) { 29 | let time = dispatch_time(DISPATCH_TIME_NOW, Int64(touchUpDuration * Double(NSEC_PER_SEC))) 30 | dispatch_after(time, dispatch_get_main_queue()) { 31 | if let target = self.target as? NSObject{ 32 | target.performSelector(self.action!, withObject: sender) 33 | } 34 | } 35 | } 36 | } 37 | 38 | 39 | class PMCaptureButton: UIButton { 40 | 41 | var lineWidth: CGFloat = 1 42 | var lineColor: UIColor = UIColor.RGBColor(78, green: 78, blue: 78) 43 | var fillColor: UIColor = UIColor.RGBColor(245, green: 245, blue: 245) 44 | var enabledColor: UIColor = UIColor.init(white: 0.98, alpha: 0.75) 45 | let content = PMCaptureButtonContent.init() 46 | var shouldLayout = true 47 | var targets: [AnyObject] = [AnyObject]() 48 | 49 | 50 | override var enabled: Bool { 51 | didSet { 52 | content.enabled = enabled 53 | } 54 | } 55 | 56 | 57 | override init(frame: CGRect) { 58 | super.init(frame: frame) 59 | backgroundColor = UIColor.clearColor() 60 | configViews() 61 | } 62 | 63 | required init?(coder aDecoder: NSCoder) { 64 | super.init(coder: aDecoder) 65 | backgroundColor = UIColor.clearColor() 66 | configViews() 67 | } 68 | 69 | func configViews() { 70 | content.backgroundColor = UIColor.clearColor() 71 | content.frame = bounds 72 | content.lineColor = lineColor 73 | content.lineWidth = lineWidth 74 | content.fillColor = fillColor 75 | content.enabledColor = enabledColor 76 | content.userInteractionEnabled = false 77 | addSubview(content) 78 | 79 | addTarget(self, action: #selector(PMCaptureButton.touchDown), forControlEvents: UIControlEvents.TouchDown) 80 | super.addTarget(self, action: #selector(PMCaptureButton.touchUpInside), forControlEvents: UIControlEvents.TouchUpInside) 81 | addTarget(self, action: #selector(PMCaptureButton.touchDragExit), forControlEvents: UIControlEvents.TouchDragExit) 82 | addTarget(self, action: #selector(PMCaptureButton.touchDragEnter), forControlEvents: UIControlEvents.TouchDragEnter) 83 | } 84 | 85 | override func layoutSubviews() { 86 | guard shouldLayout else { 87 | return 88 | } 89 | content.frame = bounds 90 | } 91 | 92 | override func addTarget(target: AnyObject?, action: Selector, forControlEvents controlEvents: UIControlEvents) { 93 | if controlEvents == .TouchUpInside { 94 | if let tar = target { 95 | let pmTarget = PMTarget.init(target: tar, action: action) 96 | super.addTarget(pmTarget, action: #selector(PMTarget.touch(_:)), forControlEvents: controlEvents) 97 | targets.append(pmTarget) // retain ARC, also could associate `pmTarget` property to `target`, and write an extension of NSObject to add a dealloc call back metohod(remove the association). 98 | } 99 | }else { 100 | super.addTarget(target, action: action, forControlEvents: controlEvents) 101 | } 102 | } 103 | 104 | 105 | func touchDown() { 106 | setSelectedState(true) 107 | } 108 | 109 | func touchUpInside() { 110 | setSelectedState(false) 111 | } 112 | 113 | func touchDragExit() { 114 | setSelectedState(false) 115 | } 116 | 117 | func touchDragEnter() { 118 | setSelectedState(true) 119 | } 120 | 121 | func setSelectedState(selected: Bool) { 122 | if selected { 123 | shouldLayout = false 124 | UIView.animateWithDuration(0.05, delay: 0, options: UIViewAnimationOptions.CurveLinear, animations: { 125 | self.content.transform = CGAffineTransformMakeScale(0.86, 0.86) 126 | }, completion: { (com: Bool) in 127 | self.shouldLayout = true 128 | }) 129 | }else { 130 | shouldLayout = false 131 | UIView.animateWithDuration(touchUpDuration, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: { 132 | self.content.transform = CGAffineTransformIdentity 133 | }, completion: { (com: Bool) in 134 | self.shouldLayout = true 135 | }) 136 | } 137 | } 138 | } 139 | 140 | class PMCaptureButtonContent: UIView { 141 | 142 | var lineWidth: CGFloat = 1 143 | var lineColor: UIColor = UIColor.blackColor() 144 | var fillColor: UIColor = UIColor.grayColor() 145 | var enabledColor: UIColor = UIColor.lightGrayColor() 146 | let screenScale: CGFloat = UIScreen.mainScreen().scale 147 | var centerOffset: CGFloat = (1.0/UIScreen.mainScreen().scale)/2 148 | private var _enabled: Bool = true 149 | var enabled: Bool { 150 | set { 151 | _enabled = newValue 152 | setNeedsDisplay() 153 | } 154 | get { 155 | return _enabled 156 | } 157 | } 158 | 159 | 160 | override func drawRect(rect: CGRect) { 161 | // Draw circle 162 | let edgeInset: CGFloat = 2 163 | let centerX = CGFloatPixelRound(bounds.size.width/2) 164 | let centerY = CGFloatPixelRound(bounds.size.height/2) 165 | let radius = CGFloatPixelRound(bounds.size.width/2 - 2 * edgeInset) 166 | if (lineWidth * screenScale)/2 == 0 { 167 | centerOffset = 0 168 | } 169 | 170 | let context = UIGraphicsGetCurrentContext() 171 | CGContextSetStrokeColorWithColor(context!, lineColor.CGColor) 172 | CGContextSetLineWidth(context!, lineWidth) 173 | CGContextSetFillColorWithColor(context!, fillColor.CGColor) 174 | CGContextAddArc(context!, centerX + centerOffset, centerY + centerOffset, radius, 0, CGFloat(M_PI) * 2, 0) 175 | CGContextDrawPath(context!, CGPathDrawingMode.FillStroke) 176 | 177 | if enabled == false { 178 | CGContextSaveGState(context!) 179 | CGContextSetFillColorWithColor(context!, enabledColor.CGColor) 180 | CGContextAddArc(context!, centerX + centerOffset, centerY + centerOffset, radius + lineWidth, 0, CGFloat(M_PI) * 2, 0) 181 | CGContextDrawPath(context!, CGPathDrawingMode.Fill) 182 | } 183 | } 184 | 185 | func CGFloatPixelRound(value: CGFloat) -> CGFloat { 186 | let scale = screenScale 187 | return round(value * scale) / scale 188 | } 189 | } 190 | 191 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaViews/PMStyleCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMStyleCell.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/8/1. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PMStyleCell: UICollectionViewCell { 12 | 13 | @IBOutlet weak var styleImageView: UIImageView! 14 | @IBOutlet weak var styleNameLabel: UILabel! 15 | @IBOutlet weak var view: UIView! 16 | @IBOutlet weak var indicator: UIActivityIndicatorView! 17 | 18 | 19 | override func layoutSubviews() { 20 | super.layoutSubviews() 21 | view.frame = bounds 22 | } 23 | 24 | func loadImage(data: AnyObject) { 25 | // Loading 26 | indicator.hidden = false 27 | indicator.startAnimating() 28 | 29 | // Ttile 30 | let title: String = data.objectForKey("artwork")! as! String 31 | self.styleNameLabel.text = title 32 | 33 | // Download image 34 | let URL: NSURL = NSURL.init(string: data.objectForKey("image_url")! as! String)! 35 | styleImageView.pm_setImageWithURL(URL) { (image: UIImage?, error: NSError?) in 36 | self.indicator.stopAnimating() 37 | self.indicator.hidden = true 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaViews/PMStyleHeaderView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMStyleHeaderView.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/8/1. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PMStyleHeaderView: UIView { 12 | 13 | var imageView = UIImageView.init() 14 | 15 | override init(frame: CGRect) { 16 | super.init(frame: frame) 17 | configSubviews() 18 | } 19 | 20 | func configSubviews() { 21 | imageView.backgroundColor = UIColor.whiteColor() 22 | imageView.frame = bounds 23 | addSubview(imageView) 24 | } 25 | 26 | override func layoutSubviews() { 27 | super.layoutSubviews() 28 | imageView.frame = bounds 29 | } 30 | 31 | func setImage(image: UIImage) { 32 | imageView.image = image 33 | } 34 | 35 | required init?(coder aDecoder: NSCoder) { 36 | fatalError("init(coder:) has not been implemented") 37 | } 38 | 39 | /* 40 | // Only override drawRect: if you perform custom drawing. 41 | // An empty implementation adversely affects performance during animation. 42 | override func drawRect(rect: CGRect) { 43 | // Drawing code 44 | } 45 | */ 46 | 47 | } 48 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaWebImage/PMImageCache.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMImageCache.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/8/5. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Compression 11 | 12 | class PMImageCache: NSObject { 13 | 14 | let imageCache: NSCache = NSCache.init() 15 | var diskPath: String? 16 | let fileManager: NSFileManager = NSFileManager.defaultManager() 17 | 18 | override init() { 19 | super.init() 20 | self.diskPath = defaultDiskPath() 21 | } 22 | 23 | func storeImage(image: UIImage, forKey: String) { 24 | let path = defaultCachePathForKey(forKey) 25 | if !fileManager.isExecutableFileAtPath(diskPath!) { 26 | try! fileManager.createDirectoryAtPath(diskPath!, withIntermediateDirectories: true, attributes: nil) 27 | } 28 | 29 | imageCache.setObject(image, forKey: forKey, cost: Int(image.size.height * image.size.width * image.scale * image.scale)) 30 | fileManager.createFileAtPath(path, contents: UIImageJPEGRepresentation(image, 1.0), attributes: nil) 31 | } 32 | 33 | func queryImageFromCache(key: String, doneBlock: ((image: UIImage?)->Void)?) { 34 | 35 | var image: UIImage? 36 | 37 | if let cacheImage = self.imageCache.objectForKey(key) { 38 | image = cacheImage as? UIImage 39 | if let done = doneBlock { 40 | done(image: image) 41 | } 42 | }else { 43 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { 44 | let path = self.defaultCachePathForKey(key) 45 | if self.fileManager.isExecutableFileAtPath(path) { 46 | let data = NSData.init(contentsOfFile: path) 47 | image = UIImage.init(data: data!) 48 | } 49 | 50 | if let done = doneBlock { 51 | dispatch_async(dispatch_get_main_queue(), { 52 | done(image: image) 53 | }) 54 | } 55 | } 56 | 57 | } 58 | } 59 | 60 | func defaultDiskPath() -> String { 61 | var path = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.CachesDirectory, .UserDomainMask, true) 62 | let diskDir: NSString = path[0] 63 | let diskPath = diskDir.stringByAppendingPathComponent("com.PMImageSimplePicker.PMImageCache") 64 | return diskPath 65 | } 66 | 67 | func defaultCachePathForKey(key: String) -> String { 68 | let path = (diskPath! as NSString).stringByAppendingPathComponent(key) 69 | return path 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaWebImage/PMImageDownloader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMImageDownloader.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/8/5. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PMSessionDelegate: NSObject { 12 | var completionHandler: ((NSData?, NSURL?, NSError?) -> Void)? 13 | var task: NSURLSessionDataTask? 14 | var mutableData: NSMutableData = NSMutableData.init() 15 | 16 | override init() { 17 | super.init() 18 | } 19 | 20 | convenience init(completionHandler: ((NSData?, NSURL?, NSError?) -> Void)?) { 21 | self.init() 22 | self.completionHandler = completionHandler 23 | } 24 | } 25 | 26 | class PMImageDownloader: NSObject, NSURLSessionDelegate, NSURLSessionDataDelegate { 27 | 28 | var session: NSURLSession? 29 | var imageCache: PMImageCache = PMImageCache.init() 30 | var taskDelegates: [String:PMSessionDelegate] = [String:PMSessionDelegate]() 31 | 32 | 33 | override init() { 34 | super.init() 35 | session = NSURLSession.init(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(), delegate: self, delegateQueue: NSOperationQueue.init()) 36 | } 37 | 38 | class func sharedDownloader() -> PMImageDownloader { 39 | struct Static { 40 | static var token: dispatch_once_t = 0 41 | static var downloader: PMImageDownloader? 42 | } 43 | 44 | dispatch_once(&Static.token) { 45 | Static.downloader = PMImageDownloader.init() 46 | } 47 | 48 | return Static.downloader! 49 | } 50 | 51 | func downloadImage(url: NSURL, completionHandler: ((image: UIImage?, URL: NSURL?, error: NSError?)->Void)) { 52 | let urlKey = url.absoluteString 53 | 54 | // Check disk 55 | weak var weakSelf = self 56 | imageCache.queryImageFromCache(urlKey!) { (image: UIImage?) in 57 | if let img: UIImage = image { 58 | if let com: ((image: UIImage?, URL: NSURL?, error: NSError?)->Void) = completionHandler { 59 | com(image: img, URL: url, error: nil) 60 | } 61 | } 62 | 63 | // Down image 64 | else { 65 | let dataTask = weakSelf!.pmDataTaskWithURL(url) { (data: NSData?, _URL: NSURL?, error: NSError?) in 66 | var image: UIImage? 67 | var error: NSError? 68 | if let err = error { 69 | error = err 70 | print("down error \(err)") 71 | }else { 72 | if data?.length > 0 { 73 | image = UIImage.init(data: data!) 74 | // Stroe image 75 | weakSelf!.imageCache.storeImage(image!, forKey: urlKey!) 76 | } 77 | } 78 | 79 | if let com: ((image: UIImage?, URL: NSURL? ,error: NSError?)->Void) = completionHandler { 80 | com(image: image, URL: _URL, error: error) 81 | } 82 | } 83 | 84 | dataTask.resume() 85 | } 86 | } 87 | 88 | } 89 | 90 | 91 | func pmDataTaskWithURL(url: NSURL, completionHandler: (NSData?, NSURL?, NSError?) -> Void) -> NSURLSessionDataTask { 92 | 93 | if let delegate = taskDelegates[url.absoluteString!] { 94 | delegate.completionHandler = completionHandler 95 | let task = delegate.task! 96 | return task 97 | } 98 | 99 | let task = self.session!.dataTaskWithURL(url) 100 | let delegate = PMSessionDelegate.init(completionHandler: completionHandler) 101 | delegate.task = task 102 | taskDelegates[url.absoluteString!] = delegate 103 | 104 | return task 105 | } 106 | 107 | // MARK: Delegate 108 | 109 | func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) { 110 | let delegate = taskDelegates[(dataTask.originalRequest?.URL?.absoluteString)!] 111 | delegate?.mutableData.appendData(data) 112 | } 113 | 114 | func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) { 115 | let delegate = taskDelegates[(task.originalRequest?.URL?.absoluteString)!] 116 | if let callBack = delegate?.completionHandler { 117 | dispatch_async(dispatch_get_main_queue(), { 118 | callBack(delegate?.mutableData, task.originalRequest?.URL, error) 119 | }) 120 | } 121 | } 122 | 123 | } 124 | 125 | var kAssociatedUrl: UInt8 = 0 126 | 127 | extension UIImageView { 128 | 129 | var currentUrl: String { 130 | set { 131 | objc_setAssociatedObject(self, &kAssociatedUrl, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 132 | } 133 | get { 134 | if let url = objc_getAssociatedObject(self, &kAssociatedUrl) { 135 | return url as! String 136 | } 137 | return "current_orginal_url" 138 | } 139 | } 140 | 141 | func pm_setImageWithURL(URL: NSURL, completionHandler:((image: UIImage?, error: NSError?)->Void)?) { 142 | self.image = nil 143 | currentUrl = URL.absoluteString! 144 | let downloader = PMImageDownloader.sharedDownloader() 145 | downloader.downloadImage(URL) { (image: UIImage?, _URL: NSURL?, error: NSError?) in 146 | 147 | guard _URL?.absoluteString == self.currentUrl else { 148 | return 149 | } 150 | 151 | if let img = image { 152 | self.image = img 153 | self.setNeedsLayout() 154 | } 155 | 156 | if let callBack = completionHandler { 157 | callBack(image: image,error: error) 158 | } 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/PrismaWebImage/PMImageSession.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PMImageSession.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/8/6. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // PrismaSimpleImagePicker 4 | // 5 | // Created by Roy lee on 16/7/24. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | // Do any additional setup after loading the view, typically from a nib. 16 | } 17 | 18 | override func didReceiveMemoryWarning() { 19 | super.didReceiveMemoryWarning() 20 | // Dispose of any resources that can be recreated. 21 | } 22 | 23 | 24 | } 25 | 26 | -------------------------------------------------------------------------------- /PrismaSimpleImagePicker/styles.json: -------------------------------------------------------------------------------- 1 | {"styles":[{"artist":"","artwork":"Femme","image_url":"https:\/\/cdn.neuralprisma.com\/images\/1507_k15.jpg","model":"1507_k15"},{"artist":"","artwork":"Udnie","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNet11_na.jpg","model":"resNet11_na"},{"artist":"","artwork":"Tears","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNet10_nd.jpg","model":"resNet10_nd"},{"artist":"","artwork":"#GettUrban","image_url":"https:\/\/cdn.neuralprisma.com\/images\/kd.jpg","model":"kd"},{"artist":"","artwork":"Marcus D - Lone Wolf","image_url":"https:\/\/cdn.neuralprisma.com\/images\/k11.jpg","model":"k11"},{"artist":"","artwork":"Dreams","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNet9_n1_1.jpg","model":"resNet9_n1"},{"artist":"","artwork":"Running in the storm","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNet11_m9_1.jpg","model":"resNet11_m9"},{"artist":"","artwork":"Curtain","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNet10_m7_1.jpg","model":"resNet10_m7"},{"artist":"","artwork":"Impression","image_url":"https:\/\/cdn.neuralprisma.com\/images\/palmolive02.jpg","model":"k3"},{"artist":"","artwork":"Flame flower","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNet10_m2.jpg","model":"resNet10_m2"},{"artist":"","artwork":"Mondrian","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNet11_nb.jpg","model":"resNet11_nb"},{"artist":"","artwork":"Paper art","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNet9_n2.jpg","model":"resNet9_n2"},{"artist":"","artwork":"Roland","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNet9_n3.jpg","model":"resNet9_n3"},{"artist":"","artwork":"Red head","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNet9_n7.jpg","model":"resNet9_n7"},{"artist":"","artwork":"Composition","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNetFinal_final5.jpg","model":"resNetFinal_final5"},{"artist":"","artwork":"Light summer reading","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNetFinal_14.jpg","model":"resNetFinal_14"},{"artist":"","artwork":"Coloured sky","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNet9_n5_1.jpg","model":"resNet9_n5"},{"artist":"","artwork":"Roy","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNet4_6.jpg","model":"resNet4_6"},{"artist":"","artwork":"Candy","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNet7_4.jpg","model":"resNet7_4"},{"artist":"","artwork":"Transverse Line","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNet8_1.jpg","model":"resNet8_1"},{"artist":"","artwork":"Mosaic","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNet8_6.jpg","model":"resNet8_6"},{"artist":"","artwork":"Heisenberg","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNetFinal_4.jpg","model":"resNetFinal_4"},{"artist":"","artwork":"Illegal Beauty","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNet7_5.jpg","model":"resNet7_5"},{"artist":"","artwork":"Mononoke","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNetFinal_8.jpg","model":"resNetFinal_8"},{"artist":"","artwork":"Urban","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNetFinal_9.jpg","model":"resNetFinal_9"},{"artist":"","artwork":"Tokyo","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNetFinal_13.jpg","model":"resNetFinal_13"},{"artist":"","artwork":"Curly Hair","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNetFinal_final0.jpg","model":"resNetFinal_final0"},{"artist":"","artwork":"Wave","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNetFinal_final1.jpg","model":"resNetFinal_final1"},{"artist":"","artwork":"Gothic","image_url":"https:\/\/cdn.neuralprisma.com\/images\/resNetFinal_final3.jpg","model":"resNetFinal_final3"}],"version":59} -------------------------------------------------------------------------------- /PrismaSimpleImagePickerTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /PrismaSimpleImagePickerTests/PrismaSimpleImagePickerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PrismaSimpleImagePickerTests.swift 3 | // PrismaSimpleImagePickerTests 4 | // 5 | // Created by Roy lee on 16/7/24. 6 | // Copyright © 2016年 Roy lee. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import PrismaSimpleImagePicker 11 | 12 | class PrismaSimpleImagePickerTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measureBlock { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PrismaSimpleImagePicker 2 | 3 | 4 | ![Logo](https://github.com/Roylee-ML/PrismaSimpleImagePicker/blob/master/ScreenShots/logo.png) 5 | 6 | 7 | Custom camera, image picker ,image editor and the interface just like Prisma's style. 8 | 9 | 10 | # Overview 11 | 12 | OverView1 13 | OverView2 14 | OverView3 15 | 16 | 17 | 18 | # Introduction 19 | 20 | ### This is just a client function copy of Prisma, not a pod solution 21 | 22 | Prisma is a sucessful APP of photo editing, but it's success is more than just art. And the details of the Prisma is also very good. So, I try to reproduce the client function of Prisma use Swift, and the result is this project. 23 | 24 | This is build with Storyboard and xib, just because the Prisma is also used Storyboard and xib. The follow is the struct: 25 | 26 | ![Struct](https://github.com/Roylee-ML/PrismaSimpleImagePicker/blob/master/ScreenShots/prismanib.png) 27 | 28 | 29 | ### What is the use of this project? 30 | 31 | **Firstly**, we can learn how to custom camera use framework AVFoundation. 32 | 33 | > * **AVCaptureSession** A session to manage camera, responsible for the video image management function 34 | > * **AVCaptureDeviceInput** Do the image acquisition 35 | > * **AVCaptureStillImageOutput** Function for image stream output 36 | > * **AVCaptureVideoPreviewLayer** Video preview layer, used to display the scene of the camera in real time 37 | 38 | There is one thing we need to pay attention when we custom a camera, it's the image's orientation. Because the normal orientation of iPhone camera is lanscape left(Home button on the right), so the image orientation is different from our expected result. Below is a comparison. 39 | 40 | ![Camera position](https://github.com/Roylee-ML/PrismaSimpleImagePicker/blob/master/ScreenShots/possion.png) 41 | 42 | 43 | **Secondly**, from this project we can learn about some kowledge of system photo album. Because just support iOS8 above, so I use framework Photos to complete photo select, not the AssetsLibrary frmawork Prisma used. And below is the frameworks Prisma used. 44 | 45 | ![Frameworks](https://github.com/Roylee-ML/PrismaSimpleImagePicker/blob/master/ScreenShots/frameworks.png) 46 | 47 | 48 | **Finally**, we could just use the image picker in foder `PrismaImagePicker`, this is an independent function for developer jsut want to have a image picker with Prisma's syle. 49 | 50 | **More details, please view my [blog](http://error408.com/2016/08/03/Prisma-%E6%88%90%E5%8A%9F%E7%9A%84%E4%B8%8D%E5%8F%AA%E6%98%AF%E8%89%BA%E6%9C%AF/)(*Only Chinese supported*)** 51 | 52 | 53 | 54 | ### How to use PrismaImagePicker? 55 | 56 | * Create an object of class `PMImagePickerController`, and just present it from your own view controller. 57 | * If you just have the data source before, you can set the data source of `PMImagePickerController`, so it can be fast because without read the photo album. 58 | * Conform to protocol `PMImagePickerControllerDelegate`, and implement the delegate used. 59 | 60 | The PMImagePickerControllerDelegate 61 | 62 | ```swift 63 | @objc protocol PMImagePickerControllerDelegate: NSObjectProtocol { 64 | /** 65 | Call when tap `Use` button of the picker view controller 66 | 67 | - parameter picker: The view controller of class PMImagePickerController 68 | - parameter image: An cropped image which displayed in the top header after edit 69 | */ 70 | optional func imagePickerController(picker: PMImagePickerController, didFinishPickingImage image: UIImage) 71 | 72 | /** 73 | Call when tap `Use` button of the picker view controller 74 | 75 | - parameter picker: The view controller of class PMImagePickerController 76 | - parameter originalImage: An original image which displayed in the top header 77 | - parameter selectedRect: A rect displayed of the header 78 | - parameter zoomScale: ZoomScale of the image 79 | */ 80 | optional func imagePickerController(picker: PMImagePickerController, didFinishPickingImage originalImage: UIImage, selectedRect: CGRect, zoomScale:CGFloat) 81 | 82 | /** 83 | Call when tap `Cancel` button of the picker view controller 84 | 85 | - parameter picker: The view controller of class PMImagePickerController 86 | */ 87 | optional func imagePickerControllerDidCancel(picker: PMImagePickerController) 88 | } 89 | ``` 90 | 91 |
92 | Create and use the iamge picker 93 | 94 | ```swift 95 | // Create image picker 96 | @IBAction func selectPhoto(sender: AnyObject) { 97 | let nav = PMImagePickerController.init() 98 | nav.pmDelegate = self 99 | nav.photoGroups = photoGroups 100 | nav.photoAssets = photoAssets 101 | weak var weakSelf = self 102 | self.presentViewController(nav, animated: true) { 103 | weakSelf!.session.stopRunning() 104 | } 105 | } 106 | 107 | 108 | // PMImagePickerControllerDelegate 109 | func imagePickerController(picker: PMImagePickerController, didFinishPickingImage originalImage: UIImage, selectedRect: CGRect, zoomScale:CGFloat) { 110 | // Do something with the original image 111 | ... 112 | } 113 | 114 | func imagePickerController(picker: PMImagePickerController, didFinishPickingImage image: UIImage) { 115 | // Dow something with the cropped image 116 | ... 117 | } 118 | 119 | func imagePickerControllerDidCancel(picker: PMImagePickerController) { 120 | session.startRunning() 121 | } 122 | ``` 123 | 124 | **Custom your own album kind** 125 | 126 | The default album is `Camera`、`Favorites`、`ScreenShots` and `User photos`, and all the operations of image is in `PMImageManger.swift`. 127 | 128 | If you want change the kind of album, you could change the parameters `PHAssetCollectionType` and `PHAssetCollectionSubtype` in function `class func photoLibrarys() -> [PHAssetCollection]` 129 | 130 | 131 | # License 132 | 133 | PrismaSimpleImagePicker is available under the MIT license. See the LICENSE file for more info. 134 | -------------------------------------------------------------------------------- /ScreenShots/cropimage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/ScreenShots/cropimage.png -------------------------------------------------------------------------------- /ScreenShots/frameworks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/ScreenShots/frameworks.png -------------------------------------------------------------------------------- /ScreenShots/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/ScreenShots/logo.png -------------------------------------------------------------------------------- /ScreenShots/possion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/ScreenShots/possion.png -------------------------------------------------------------------------------- /ScreenShots/prismanib.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/ScreenShots/prismanib.png -------------------------------------------------------------------------------- /ScreenShots/screenshot1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/ScreenShots/screenshot1.gif -------------------------------------------------------------------------------- /ScreenShots/screenshot2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/ScreenShots/screenshot2.gif -------------------------------------------------------------------------------- /ScreenShots/screenshot3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liangdrime/PrismaSimpleImagePicker/4c33274fa2cceec436b42aa8205d42a393a27c13/ScreenShots/screenshot3.gif --------------------------------------------------------------------------------