├── .DS_Store ├── .gitignore ├── Info.plist ├── LICENSE ├── PureCamera.podspec ├── PureCamera ├── LLSimpleCamera+Helper.h ├── LLSimpleCamera+Helper.m ├── LLSimpleCamera.h ├── LLSimpleCamera.m ├── PureCamera.bundle │ ├── camera-flash.png │ ├── camera-flash@2x.png │ ├── cameraButton.png │ ├── cameraButton@2x.png │ ├── cameraButton@3x.png │ ├── closeButton.png │ ├── closeButton@2x.png │ ├── closeButton@3x.png │ ├── en.lproj │ │ └── Root.strings │ ├── swapButton.png │ ├── swapButton@2x.png │ └── swapButton@3x.png ├── PureCamera.h ├── PureCamera.m ├── PureCropVC.h ├── PureCropVC.m ├── TOActivityCroppedImageProvider.h ├── TOActivityCroppedImageProvider.m ├── TOCropOverlayView.h ├── TOCropOverlayView.m ├── TOCropScrollView.h ├── TOCropScrollView.m ├── TOCropToolbar.h ├── TOCropToolbar.m ├── TOCropView.h ├── TOCropView.m ├── TOCropViewController.h ├── TOCropViewController.m ├── TOCropViewControllerLocalizable.strings ├── TOCropViewControllerTransitioning.h ├── TOCropViewControllerTransitioning.m ├── TOCroppedImageAttributes.h ├── TOCroppedImageAttributes.m ├── UIImage+CropRotate.h ├── UIImage+CropRotate.m ├── UIImage+FixOrientation.h └── UIImage+FixOrientation.m ├── PureCamerademo.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ ├── shiyue.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ └── sunkaifeng.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ ├── shiyue.xcuserdatad │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ │ └── xcschememanagement.plist │ └── sunkaifeng.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── PureCamerademo └── PureCamerademo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ ├── 1.imageset │ │ ├── C8AECEE3EC242CAA4442358F3D912F9A.jpg │ │ └── Contents.json │ ├── 2.imageset │ │ ├── Contents.json │ │ └── FE00349D152834B01E38D3F64A9D1217.jpg │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── KModel.h │ ├── KModel.m │ ├── ViewController.h │ ├── ViewController.m │ └── main.m ├── README.md └── azure-pipelines.yml /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wubianxiaoxian/PureCamera-Demo/31a8a0970774561ceab0b29c7829388ee802f992/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /PureCamerademo.xcodeproj/xcuserdata 2 | /PureCamerademo.xcodeproj/project.xcworkspace/xcuserdata 3 | Podfile.lock 4 | /Pods 5 | /PureCamerademo.xcworkspace 6 | .DS_Store 7 | 8 | -------------------------------------------------------------------------------- /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 | APPL 17 | CFBundleShortVersionString 18 | 1.6.3 19 | CFBundleVersion 20 | 180508 21 | LSRequiresIPhoneOS 22 | 23 | NSCameraUsageDescription 24 | 使用相机 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 wubianxiaoxian 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 | -------------------------------------------------------------------------------- /PureCamera.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint Purecamera.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | Pod::Spec.new do |s| 9 | s.name = 'PureCamera' 10 | s.version = '1.6.3' 11 | s.summary = "This one can customize the camera to take pictures of the page of the library, but also to support the cutting of the photo when the camera is completed." 12 | s.license = "MIT" 13 | s.description = 'This one can customize the camera to take pictures of the page of the library, but also to support the cutting of the photo when the camera is completed.thanyou' 14 | s.homepage = "https://github.com/wubianxiaoxian/PureCamera-Demo" 15 | s.screenshots = "http://i1.piimg.com/4851/0071da17a0c177d6.gif" 16 | s.author = { 'Kaifeng Sun' => 'sunkaifengdiyi@163.com' } 17 | s.platform = :ios, "8.1" 18 | s.source_files = 'PureCamera/**/*' 19 | s.resource = "PureCamera/PureCamera.bundle" 20 | s.requires_arc = true 21 | s.framework = "UIKit" 22 | s.source = { :git => "https://github.com/wubianxiaoxian/PureCamera-Demo.git", :tag =>s.version } 23 | end 24 | 25 | -------------------------------------------------------------------------------- /PureCamera/LLSimpleCamera+Helper.h: -------------------------------------------------------------------------------- 1 | // 2 | // LLSimpleCamera+Helper.h 3 | // LLSimpleCameraExample 4 | // 5 | // Created by Ömer Faruk Gül on 20/02/16. 6 | // Copyright © 2016 Ömer Faruk Gül. All rights reserved. 7 | // 8 | 9 | #import "LLSimpleCamera.h" 10 | 11 | @interface LLSimpleCamera (Helper) 12 | 13 | - (CGPoint)convertToPointOfInterestFromViewCoordinates:(CGPoint)viewCoordinates 14 | previewLayer:(AVCaptureVideoPreviewLayer *)previewLayer 15 | ports:(NSArray *)ports; 16 | 17 | - (UIImage *)cropImage:(UIImage *)image usingPreviewLayer:(AVCaptureVideoPreviewLayer *)previewLayer; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /PureCamera/LLSimpleCamera+Helper.m: -------------------------------------------------------------------------------- 1 | // 2 | // LLSimpleCamera+Helper.m 3 | // LLSimpleCameraExample 4 | // 5 | // Created by Ömer Faruk Gül on 20/02/16. 6 | // Copyright © 2016 Ömer Faruk Gül. All rights reserved. 7 | // 8 | 9 | #import "LLSimpleCamera+Helper.h" 10 | 11 | @implementation LLSimpleCamera (Helper) 12 | 13 | - (CGPoint)convertToPointOfInterestFromViewCoordinates:(CGPoint)viewCoordinates 14 | previewLayer:(AVCaptureVideoPreviewLayer *)previewLayer 15 | ports:(NSArray *)ports 16 | { 17 | CGPoint pointOfInterest = CGPointMake(.5f, .5f); 18 | CGSize frameSize = previewLayer.frame.size; 19 | 20 | if ( [previewLayer.videoGravity isEqualToString:AVLayerVideoGravityResize] ) { 21 | pointOfInterest = CGPointMake(viewCoordinates.y / frameSize.height, 1.f - (viewCoordinates.x / frameSize.width)); 22 | } else { 23 | CGRect cleanAperture; 24 | for (AVCaptureInputPort *port in ports) { 25 | if (port.mediaType == AVMediaTypeVideo) { 26 | cleanAperture = CMVideoFormatDescriptionGetCleanAperture([port formatDescription], YES); 27 | CGSize apertureSize = cleanAperture.size; 28 | CGPoint point = viewCoordinates; 29 | 30 | CGFloat apertureRatio = apertureSize.height / apertureSize.width; 31 | CGFloat viewRatio = frameSize.width / frameSize.height; 32 | CGFloat xc = .5f; 33 | CGFloat yc = .5f; 34 | 35 | if ( [previewLayer.videoGravity isEqualToString:AVLayerVideoGravityResizeAspect] ) { 36 | if (viewRatio > apertureRatio) { 37 | CGFloat y2 = frameSize.height; 38 | CGFloat x2 = frameSize.height * apertureRatio; 39 | CGFloat x1 = frameSize.width; 40 | CGFloat blackBar = (x1 - x2) / 2; 41 | if (point.x >= blackBar && point.x <= blackBar + x2) { 42 | xc = point.y / y2; 43 | yc = 1.f - ((point.x - blackBar) / x2); 44 | } 45 | } else { 46 | CGFloat y2 = frameSize.width / apertureRatio; 47 | CGFloat y1 = frameSize.height; 48 | CGFloat x2 = frameSize.width; 49 | CGFloat blackBar = (y1 - y2) / 2; 50 | if (point.y >= blackBar && point.y <= blackBar + y2) { 51 | xc = ((point.y - blackBar) / y2); 52 | yc = 1.f - (point.x / x2); 53 | } 54 | } 55 | } else if ([previewLayer.videoGravity isEqualToString:AVLayerVideoGravityResizeAspectFill]) { 56 | if (viewRatio > apertureRatio) { 57 | CGFloat y2 = apertureSize.width * (frameSize.width / apertureSize.height); 58 | xc = (point.y + ((y2 - frameSize.height) / 2.f)) / y2; 59 | yc = (frameSize.width - point.x) / frameSize.width; 60 | } else { 61 | CGFloat x2 = apertureSize.height * (frameSize.height / apertureSize.width); 62 | yc = 1.f - ((point.x + ((x2 - frameSize.width) / 2)) / x2); 63 | xc = point.y / frameSize.height; 64 | } 65 | } 66 | 67 | pointOfInterest = CGPointMake(xc, yc); 68 | break; 69 | } 70 | } 71 | } 72 | 73 | return pointOfInterest; 74 | } 75 | 76 | - (UIImage *)cropImage:(UIImage *)image usingPreviewLayer:(AVCaptureVideoPreviewLayer *)previewLayer 77 | { 78 | CGRect previewBounds = previewLayer.bounds; 79 | CGRect outputRect = [previewLayer metadataOutputRectOfInterestForRect:previewBounds]; 80 | 81 | CGImageRef takenCGImage = image.CGImage; 82 | size_t width = CGImageGetWidth(takenCGImage); 83 | size_t height = CGImageGetHeight(takenCGImage); 84 | CGRect cropRect = CGRectMake(outputRect.origin.x * width, outputRect.origin.y * height, 85 | outputRect.size.width * width, outputRect.size.height * height); 86 | 87 | CGImageRef cropCGImage = CGImageCreateWithImageInRect(takenCGImage, cropRect); 88 | image = [UIImage imageWithCGImage:cropCGImage scale:1 orientation:image.imageOrientation]; 89 | CGImageRelease(cropCGImage); 90 | 91 | return image; 92 | } 93 | 94 | @end 95 | -------------------------------------------------------------------------------- /PureCamera/LLSimpleCamera.h: -------------------------------------------------------------------------------- 1 | // 2 | // CameraViewController.h 3 | // LLSimpleCamera 4 | // 5 | // Created by Ömer Faruk Gül on 24/10/14. 6 | // Copyright (c) 2014 Ömer Farul Gül. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | typedef enum : NSUInteger { 13 | LLCameraPositionRear, 14 | LLCameraPositionFront 15 | } LLCameraPosition; 16 | 17 | typedef enum : NSUInteger { 18 | // The default state has to be off 19 | LLCameraFlashOff, 20 | LLCameraFlashOn, 21 | LLCameraFlashAuto 22 | } LLCameraFlash; 23 | 24 | typedef enum : NSUInteger { 25 | // The default state has to be off 26 | LLCameraMirrorOff, 27 | LLCameraMirrorOn, 28 | LLCameraMirrorAuto 29 | } LLCameraMirror; 30 | 31 | extern NSString *const LLSimpleCameraErrorDomain; 32 | typedef enum : NSUInteger { 33 | LLSimpleCameraErrorCodeCameraPermission = 10, 34 | LLSimpleCameraErrorCodeMicrophonePermission = 11, 35 | LLSimpleCameraErrorCodeSession = 12, 36 | LLSimpleCameraErrorCodeVideoNotEnabled = 13 37 | } LLSimpleCameraErrorCode; 38 | 39 | @interface LLSimpleCamera : UIViewController 40 | 41 | /** 42 | * Triggered on device change. 43 | */ 44 | @property (nonatomic, copy) void (^onDeviceChange)(LLSimpleCamera *camera, AVCaptureDevice *device); 45 | 46 | /** 47 | * Triggered on any kind of error. 48 | */ 49 | @property (nonatomic, copy) void (^onError)(LLSimpleCamera *camera, NSError *error); 50 | 51 | /** 52 | * Triggered when camera starts recording 53 | */ 54 | @property (nonatomic, copy) void (^onStartRecording)(LLSimpleCamera* camera); 55 | 56 | /** 57 | * Camera quality, set a constants prefixed with AVCaptureSessionPreset. 58 | * Make sure to call before calling -(void)initialize method, otherwise it would be late. 59 | */ 60 | @property (copy, nonatomic) NSString *cameraQuality; 61 | 62 | /** 63 | * Camera flash mode. 64 | */ 65 | @property (nonatomic, readonly) LLCameraFlash flash; 66 | 67 | /** 68 | * Camera mirror mode. 69 | */ 70 | @property (nonatomic) LLCameraMirror mirror; 71 | 72 | /** 73 | * Position of the camera. 74 | */ 75 | @property (nonatomic) LLCameraPosition position; 76 | 77 | /** 78 | * White balance mode. Default is: AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance 79 | */ 80 | @property (nonatomic) AVCaptureWhiteBalanceMode whiteBalanceMode; 81 | 82 | /** 83 | * Boolean value to indicate if the video is enabled. 84 | */ 85 | @property (nonatomic, getter=isVideoEnabled) BOOL videoEnabled; 86 | 87 | /** 88 | * Boolean value to indicate if the camera is recording a video at the current moment. 89 | */ 90 | @property (nonatomic, getter=isRecording) BOOL recording; 91 | 92 | /** 93 | * Boolean value to indicate if zooming is enabled. 94 | */ 95 | @property (nonatomic, getter=isZoomingEnabled) BOOL zoomingEnabled; 96 | 97 | /** 98 | * Float value to set maximum scaling factor 99 | */ 100 | @property (nonatomic, assign) CGFloat maxScale; 101 | 102 | /** 103 | * Fixess the orientation after the image is captured is set to Yes. 104 | * see: http://stackoverflow.com/questions/5427656/ios-uiimagepickercontroller-result-image-orientation-after-upload 105 | */ 106 | @property (nonatomic) BOOL fixOrientationAfterCapture; 107 | 108 | /** 109 | * Set NO if you don't want ot enable user triggered focusing. Enabled by default. 110 | */ 111 | @property (nonatomic) BOOL tapToFocus; 112 | 113 | /** 114 | * Set YES if you your view controller does not allow autorotation, 115 | * however you want to take the device rotation into account no matter what. Disabled by default. 116 | */ 117 | @property (nonatomic) BOOL useDeviceOrientation; 118 | 119 | /** 120 | * Use this method to request camera permission before initalizing LLSimpleCamera. 121 | */ 122 | + (void)requestCameraPermission:(void (^)(BOOL granted))completionBlock; 123 | 124 | /** 125 | * Use this method to request microphone permission before initalizing LLSimpleCamera. 126 | */ 127 | + (void)requestMicrophonePermission:(void (^)(BOOL granted))completionBlock; 128 | 129 | /** 130 | * Returns an instance of LLSimpleCamera with the given quality. 131 | * Quality parameter could be any variable starting with AVCaptureSessionPreset. 132 | */ 133 | - (instancetype)initWithQuality:(NSString *)quality position:(LLCameraPosition)position; 134 | 135 | 136 | 137 | /** 138 | * Starts running the camera session. 139 | */ 140 | - (void)start; 141 | 142 | /** 143 | * Stops the running camera session. Needs to be called when the app doesn't show the view. 144 | */ 145 | - (void)stop; 146 | 147 | 148 | /** 149 | * Capture an image. 150 | * @param onCapture a block triggered after the capturing the photo. 151 | * @param exactSeenImage If set YES, then the image is cropped to the exact size as the preview. So you get exactly what you see. 152 | * @param animationBlock you can create your own animation by playing with preview layer. 153 | */ 154 | -(void)capture:(void (^)(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error))onCapture exactSeenImage:(BOOL)exactSeenImage animationBlock:(void (^)(AVCaptureVideoPreviewLayer *))animationBlock; 155 | 156 | /** 157 | * Capture an image. 158 | * @param onCapture a block triggered after the capturing the photo. 159 | * @param exactSeenImage If set YES, then the image is cropped to the exact size as the preview. So you get exactly what you see. 160 | */ 161 | -(void)capture:(void (^)(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error))onCapture exactSeenImage:(BOOL)exactSeenImage; 162 | 163 | /** 164 | * Capture an image. 165 | * @param onCapture a block triggered after the capturing the photo. 166 | */ 167 | -(void)capture:(void (^)(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error))onCapture; 168 | 169 | /** 170 | * Attaches the LLSimpleCamera to another view controller with a frame. It basically adds the LLSimpleCamera as a 171 | * child vc to the given vc. 172 | * @param vc A view controller. 173 | * @param frame The frame of the camera. 174 | */ 175 | - (void)attachToViewController:(UIViewController *)vc withFrame:(CGRect)frame; 176 | 177 | /** 178 | * Changes the posiition of the camera (either back or front) and returns the final position. 179 | */ 180 | - (LLCameraPosition)togglePosition; 181 | 182 | /** 183 | * Update the flash mode of the camera. Returns true if it is successful. Otherwise false. 184 | */ 185 | - (BOOL)updateFlashMode:(LLCameraFlash)cameraFlash; 186 | 187 | /** 188 | * Checks if flash is avilable for the currently active device. 189 | */ 190 | - (BOOL)isFlashAvailable; 191 | 192 | /** 193 | * Checks if torch (flash for video) is avilable for the currently active device. 194 | */ 195 | - (BOOL)isTorchAvailable; 196 | 197 | /** 198 | * Alter the layer and the animation displayed when the user taps on screen. 199 | * @param layer Layer to be displayed 200 | * @param animation to be applied after the layer is shown 201 | */ 202 | - (void)alterFocusBox:(CALayer *)layer animation:(CAAnimation *)animation; 203 | 204 | /** 205 | * Checks is the front camera is available. 206 | */ 207 | + (BOOL)isFrontCameraAvailable; 208 | 209 | /** 210 | * Checks is the rear camera is available. 211 | */ 212 | + (BOOL)isRearCameraAvailable; 213 | @end 214 | -------------------------------------------------------------------------------- /PureCamera/PureCamera.bundle/camera-flash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wubianxiaoxian/PureCamera-Demo/31a8a0970774561ceab0b29c7829388ee802f992/PureCamera/PureCamera.bundle/camera-flash.png -------------------------------------------------------------------------------- /PureCamera/PureCamera.bundle/camera-flash@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wubianxiaoxian/PureCamera-Demo/31a8a0970774561ceab0b29c7829388ee802f992/PureCamera/PureCamera.bundle/camera-flash@2x.png -------------------------------------------------------------------------------- /PureCamera/PureCamera.bundle/cameraButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wubianxiaoxian/PureCamera-Demo/31a8a0970774561ceab0b29c7829388ee802f992/PureCamera/PureCamera.bundle/cameraButton.png -------------------------------------------------------------------------------- /PureCamera/PureCamera.bundle/cameraButton@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wubianxiaoxian/PureCamera-Demo/31a8a0970774561ceab0b29c7829388ee802f992/PureCamera/PureCamera.bundle/cameraButton@2x.png -------------------------------------------------------------------------------- /PureCamera/PureCamera.bundle/cameraButton@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wubianxiaoxian/PureCamera-Demo/31a8a0970774561ceab0b29c7829388ee802f992/PureCamera/PureCamera.bundle/cameraButton@3x.png -------------------------------------------------------------------------------- /PureCamera/PureCamera.bundle/closeButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wubianxiaoxian/PureCamera-Demo/31a8a0970774561ceab0b29c7829388ee802f992/PureCamera/PureCamera.bundle/closeButton.png -------------------------------------------------------------------------------- /PureCamera/PureCamera.bundle/closeButton@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wubianxiaoxian/PureCamera-Demo/31a8a0970774561ceab0b29c7829388ee802f992/PureCamera/PureCamera.bundle/closeButton@2x.png -------------------------------------------------------------------------------- /PureCamera/PureCamera.bundle/closeButton@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wubianxiaoxian/PureCamera-Demo/31a8a0970774561ceab0b29c7829388ee802f992/PureCamera/PureCamera.bundle/closeButton@3x.png -------------------------------------------------------------------------------- /PureCamera/PureCamera.bundle/en.lproj/Root.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wubianxiaoxian/PureCamera-Demo/31a8a0970774561ceab0b29c7829388ee802f992/PureCamera/PureCamera.bundle/en.lproj/Root.strings -------------------------------------------------------------------------------- /PureCamera/PureCamera.bundle/swapButton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wubianxiaoxian/PureCamera-Demo/31a8a0970774561ceab0b29c7829388ee802f992/PureCamera/PureCamera.bundle/swapButton.png -------------------------------------------------------------------------------- /PureCamera/PureCamera.bundle/swapButton@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wubianxiaoxian/PureCamera-Demo/31a8a0970774561ceab0b29c7829388ee802f992/PureCamera/PureCamera.bundle/swapButton@2x.png -------------------------------------------------------------------------------- /PureCamera/PureCamera.bundle/swapButton@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wubianxiaoxian/PureCamera-Demo/31a8a0970774561ceab0b29c7829388ee802f992/PureCamera/PureCamera.bundle/swapButton@3x.png -------------------------------------------------------------------------------- /PureCamera/PureCamera.h: -------------------------------------------------------------------------------- 1 | /*! 2 | @abstract 3 | 4 | */ 5 | #import 6 | #import "TOCropViewController.h" 7 | 8 | typedef void (^fininshcapture)(UIImage *image); 9 | @interface PureCamera : UIViewController 10 | @property (nonatomic,copy) fininshcapture fininshcapture; 11 | //@property (nonatomic,assign) fininshcapture fininshcapture; 12 | @property (nonatomic, assign) TOCropViewControllerAspectRatio aspectRatioStle; 13 | 14 | 15 | 16 | 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /PureCamera/PureCamera.m: -------------------------------------------------------------------------------- 1 | /*! 2 | @abstract 3 | Created by 孙凯峰 on 2016/10/18. 4 | */ 5 | #define KScreenSize [UIScreen mainScreen].bounds.size 6 | #define KScreenwidth [UIScreen mainScreen].bounds.size.width 7 | #define KScreenheight [UIScreen mainScreen].bounds.size.height 8 | #define IsIphone6P KScreenSize.width==414 9 | #define IsIphone6 KScreenSize.width==375 10 | #define IsIphone5S KScreenSize.height==568 11 | #define IsIphone5 KScreenSize.height==568 12 | //456字体大小 13 | #define KIOS_Iphone456(iphone6p,iphone6,iphone5s,iphone5,iphone4s) (IsIphone6P?iphone6p:(IsIphone6?iphone6:((IsIphone5S||IsIphone5)?iphone5s:iphone4s))) 14 | //宽高 15 | #define KIphoneSize_Widith(iphone6) (IsIphone6P?1.104*iphone6:(IsIphone6?iphone6:((IsIphone5S||IsIphone5)?0.853*iphone6:0.853*iphone6))) 16 | #define KIphoneSize_Height(iphone6) (IsIphone6P?1.103*iphone6:(IsIphone6?iphone6:((IsIphone5S||IsIphone5)?0.851*iphone6:0.720*iphone6))) 17 | #import "PureCamera.h" 18 | #import "TOCropViewController.h" 19 | #import "LLSimpleCamera.h" 20 | 21 | @interface PureCamera () 22 | @property (strong, nonatomic) LLSimpleCamera *camera; 23 | @property (strong, nonatomic) UILabel *errorLabel; 24 | @property (strong, nonatomic) UIButton *snapButton; 25 | @property (strong, nonatomic) UIButton *switchButton; 26 | @property (strong, nonatomic) UIButton *flashButton; 27 | @property (strong, nonatomic) UIButton *backButton; 28 | 29 | @end 30 | 31 | @implementation PureCamera 32 | 33 | - (void)viewDidLoad 34 | { 35 | [super viewDidLoad]; 36 | //拍照按钮 37 | [self InitializeCamera]; 38 | NSBundle *bundle = [NSBundle bundleWithPath:[[NSBundle bundleForClass:[self class]] pathForResource:@"PureCamera" ofType:@"bundle"]]; 39 | self.snapButton = [UIButton buttonWithType:UIButtonTypeCustom]; 40 | self.snapButton.clipsToBounds = YES; 41 | self.snapButton.layer.cornerRadius =75 / 2.0f; 42 | UIImage *snapImg = [UIImage imageNamed:@"cameraButton" inBundle:bundle compatibleWithTraitCollection:nil]; 43 | [self.snapButton setImage:snapImg forState:UIControlStateNormal]; 44 | [self.snapButton addTarget:self action:@selector(snapButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; 45 | [self.view addSubview:self.snapButton]; 46 | //闪关灯按钮 47 | self.flashButton = [UIButton buttonWithType:UIButtonTypeSystem]; 48 | 49 | self.flashButton.tintColor = [UIColor whiteColor]; 50 | UIImage *flashImg = [UIImage imageNamed:@"camera-flash" inBundle:bundle compatibleWithTraitCollection:nil]; 51 | [self.flashButton setImage:flashImg forState:UIControlStateNormal]; 52 | self.flashButton.imageEdgeInsets = UIEdgeInsetsMake(10.0f, 10.0f, 10.0f, 10.0f); 53 | [self.flashButton addTarget:self action:@selector(flashButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; 54 | [self.view addSubview:self.flashButton]; 55 | if([LLSimpleCamera isFrontCameraAvailable] && [LLSimpleCamera isRearCameraAvailable]) { 56 | //摄像头转换按钮 57 | self.switchButton = [UIButton buttonWithType:UIButtonTypeCustom]; 58 | UIImage *switchhImg = [UIImage imageNamed:@"swapButton" inBundle:bundle compatibleWithTraitCollection:nil]; 59 | [self.switchButton setImage:switchhImg forState:UIControlStateNormal]; 60 | [self.switchButton addTarget:self action:@selector(switchButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; 61 | [self.view addSubview:self.switchButton]; 62 | //返回按钮 63 | self.backButton = [UIButton buttonWithType:UIButtonTypeCustom]; 64 | UIImage *closeImage= [UIImage imageNamed:@"closeButton" inBundle:bundle compatibleWithTraitCollection:nil]; 65 | [self.backButton setImage:closeImage forState:UIControlStateNormal]; 66 | [self.backButton addTarget:self action:@selector(backButtonPressed:) forControlEvents:UIControlEventTouchUpInside]; 67 | [self.view addSubview:self.backButton]; 68 | } 69 | 70 | } 71 | 72 | 73 | - (void)viewWillAppear:(BOOL)animated 74 | { 75 | [super viewWillAppear:animated]; 76 | self.view.backgroundColor = [UIColor blackColor]; 77 | [self.navigationController setNavigationBarHidden:YES animated:NO]; 78 | // snap button to capture image 79 | 80 | //判断前后摄像头是否可用 81 | 82 | 83 | // start the camera 84 | [self.camera start]; 85 | } 86 | #pragma mark ------------- 初始化相机-------------- 87 | -(void)InitializeCamera{ 88 | CGRect screenRect = self.view.frame; 89 | 90 | // 创建一个相机 91 | self.camera = [[LLSimpleCamera alloc] initWithQuality:AVCaptureSessionPresetHigh position:LLCameraPositionRear]; 92 | 93 | // attach to a view controller 94 | [self.camera attachToViewController:self withFrame:CGRectMake(0, 0, screenRect.size.width, screenRect.size.height)]; 95 | 96 | self.camera.fixOrientationAfterCapture = NO; 97 | 98 | // take the required actions on a device change 99 | __weak typeof(self) weakSelf = self; 100 | [self.camera setOnDeviceChange:^(LLSimpleCamera *camera, AVCaptureDevice * device) { 101 | 102 | NSLog(@"Device changed."); 103 | 104 | // device changed, check if flash is available 105 | if([camera isFlashAvailable]) { 106 | weakSelf.flashButton.hidden = NO; 107 | 108 | if(camera.flash == LLCameraFlashOff) { 109 | weakSelf.flashButton.selected = NO; 110 | } 111 | else { 112 | weakSelf.flashButton.selected = YES; 113 | } 114 | } 115 | else { 116 | weakSelf.flashButton.hidden = YES; 117 | } 118 | }]; 119 | 120 | [self.camera setOnError:^(LLSimpleCamera *camera, NSError *error) { 121 | NSLog(@"Camera error: %@", error); 122 | 123 | if([error.domain isEqualToString:LLSimpleCameraErrorDomain]) { 124 | if(error.code == LLSimpleCameraErrorCodeCameraPermission) { 125 | if(weakSelf.errorLabel) { 126 | [weakSelf.errorLabel removeFromSuperview]; 127 | } 128 | UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero]; 129 | label.text = @"未获取相机权限"; 130 | label.numberOfLines = 2; 131 | label.lineBreakMode = NSLineBreakByWordWrapping; 132 | label.backgroundColor = [UIColor clearColor]; 133 | label.font = [UIFont fontWithName:@"AvenirNext-DemiBold" size:13.0f]; 134 | label.textColor = [UIColor whiteColor]; 135 | label.textAlignment = NSTextAlignmentCenter; 136 | [label sizeToFit]; 137 | label.center = CGPointMake(screenRect.size.width / 2.0f, screenRect.size.height / 2.0f); 138 | weakSelf.errorLabel = label; 139 | [weakSelf.view addSubview:weakSelf.errorLabel]; 140 | } 141 | } 142 | }]; 143 | 144 | 145 | } 146 | 147 | /* camera button methods */ 148 | 149 | - (void)switchButtonPressed:(UIButton *)button 150 | { 151 | [self.camera togglePosition]; 152 | } 153 | -(void)backButtonPressed:(UIButton *)button{ 154 | [self dismissViewControllerAnimated:YES completion:nil]; 155 | } 156 | - (NSURL *)applicationDocumentsDirectory 157 | { 158 | return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; 159 | } 160 | 161 | - (void)flashButtonPressed:(UIButton *)button 162 | { 163 | if(self.camera.flash == LLCameraFlashOff) { 164 | BOOL done = [self.camera updateFlashMode:LLCameraFlashOn]; 165 | if(done) { 166 | self.flashButton.selected = YES; 167 | self.flashButton.tintColor = [UIColor yellowColor]; 168 | } 169 | } 170 | else { 171 | BOOL done = [self.camera updateFlashMode:LLCameraFlashOff]; 172 | if(done) { 173 | self.flashButton.selected = NO; 174 | self.flashButton.tintColor = [UIColor whiteColor]; 175 | } 176 | } 177 | } 178 | #pragma mark -------------拍照-------------- 179 | 180 | - (void)snapButtonPressed:(UIButton *)button 181 | { 182 | __weak typeof(self) weakSelf = self; 183 | // 去拍照 184 | [self.camera capture:^(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error) { 185 | NSLog(@"拍照结束"); 186 | if(!error) { 187 | TOCropViewControllerAspectRatio aspectRatioStle = TOCropViewControllerAspectRatioOriginal; 188 | if (self.aspectRatioStle) { 189 | aspectRatioStle = self.aspectRatioStle; 190 | } 191 | TOCropViewController *cropController = [[TOCropViewController alloc] initWithImage:image aspectRatioStle:aspectRatioStle]; 192 | cropController.delegate = self; 193 | [weakSelf presentViewController:cropController animated:YES completion:nil]; 194 | } 195 | else { 196 | NSLog(@"An error has occured: %@", error); 197 | } 198 | } exactSeenImage:YES]; 199 | } 200 | 201 | - (void)viewWillLayoutSubviews 202 | { 203 | [super viewWillLayoutSubviews]; 204 | self.camera.view.frame=self.view.frame; 205 | self.snapButton.frame=CGRectMake((KScreenwidth-KIphoneSize_Widith(75))/2, KScreenheight-KIphoneSize_Widith(90), KIphoneSize_Widith(75), KIphoneSize_Widith(75)); 206 | self.flashButton.frame=CGRectMake((KScreenwidth-KIphoneSize_Widith(36))/2, 25, KIphoneSize_Widith(36), KIphoneSize_Widith(44)); 207 | self.switchButton.frame=CGRectMake(KScreenwidth-50, KScreenheight-KIphoneSize_Widith(75), KIphoneSize_Widith(45), KIphoneSize_Widith(45)); 208 | self.backButton.frame=CGRectMake(5, KScreenheight-KIphoneSize_Widith(75), KIphoneSize_Widith(45), KIphoneSize_Widith(45)); 209 | } 210 | - (void)cropViewController:(TOCropViewController *)cropViewController didCropToImage:(UIImage *)image withRect:(CGRect)cropRect angle:(NSInteger)angle{ 211 | self.view.alpha = 0; 212 | self.fininshcapture(image); 213 | [self dismissViewControllerAnimated:NO completion:^{ 214 | }]; 215 | [self dismissViewControllerAnimated:NO completion:^{ 216 | }]; 217 | } 218 | - (BOOL)prefersStatusBarHidden 219 | { 220 | return YES; 221 | } 222 | 223 | - (void)didReceiveMemoryWarning 224 | { 225 | [super didReceiveMemoryWarning]; 226 | } 227 | 228 | 229 | @end 230 | -------------------------------------------------------------------------------- /PureCamera/PureCropVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // PureCropVC.h 3 | // PureCamerademo 4 | // 5 | // Created by 五月 on 2018/4/4. 6 | // Copyright © 2018年 五月. All rights reserved. 7 | // 8 | 9 | #import "TOCropViewController.h" 10 | 11 | @interface PureCropVC : TOCropViewController 12 | //@property(nonatomic,assign) TOCropViewControllerAspectRatio AspectRatio; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /PureCamera/PureCropVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // PureCropVC.m 3 | // PureCamerademo 4 | // 5 | // Created by 五月 on 2018/4/4. 6 | // Copyright © 2018年 五月. All rights reserved. 7 | // 8 | 9 | #import "PureCropVC.h" 10 | 11 | @interface PureCropVC () 12 | 13 | @end 14 | 15 | @implementation PureCropVC 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | // Do any additional setup after loading the view. 20 | } 21 | 22 | - (void)didReceiveMemoryWarning { 23 | [super didReceiveMemoryWarning]; 24 | // Dispose of any resources that can be recreated. 25 | } 26 | 27 | /* 28 | #pragma mark - Navigation 29 | 30 | // In a storyboard-based application, you will often want to do a little preparation before navigation 31 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 32 | // Get the new view controller using [segue destinationViewController]. 33 | // Pass the selected object to the new view controller. 34 | } 35 | */ 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /PureCamera/TOActivityCroppedImageProvider.h: -------------------------------------------------------------------------------- 1 | // 2 | // TOActivityCroppedImageProvider.h 3 | // 4 | // Copyright 2015 Timothy Oliver. All rights reserved. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | #import 24 | 25 | @interface TOActivityCroppedImageProvider : UIActivityItemProvider 26 | 27 | @property (nonatomic, readonly) UIImage *image; 28 | @property (nonatomic, readonly) CGRect cropFrame; 29 | @property (nonatomic, readonly) NSInteger angle; 30 | 31 | - (instancetype)initWithImage:(UIImage *)image cropFrame:(CGRect)cropFrame angle:(NSInteger)angle; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /PureCamera/TOActivityCroppedImageProvider.m: -------------------------------------------------------------------------------- 1 | // 2 | // TOActivityCroppedImageProvider.m 3 | // 4 | // Copyright 2015 Timothy Oliver. All rights reserved. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | #import "TOActivityCroppedImageProvider.h" 24 | #import "UIImage+CropRotate.h" 25 | 26 | @interface TOActivityCroppedImageProvider () 27 | 28 | @property (nonatomic, strong, readwrite) UIImage *image; 29 | @property (nonatomic, assign, readwrite) CGRect cropFrame; 30 | @property (nonatomic, assign, readwrite) NSInteger angle; 31 | 32 | @property (atomic, strong) UIImage *croppedImage; 33 | 34 | @end 35 | 36 | @implementation TOActivityCroppedImageProvider 37 | 38 | - (instancetype)initWithImage:(UIImage *)image cropFrame:(CGRect)cropFrame angle:(NSInteger)angle 39 | { 40 | if (self = [super initWithPlaceholderItem:[UIImage new]]) { 41 | _image = image; 42 | _cropFrame = cropFrame; 43 | _angle = angle; 44 | } 45 | 46 | return self; 47 | } 48 | 49 | #pragma mark - UIActivity Protocols - 50 | - (id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController 51 | { 52 | return [[UIImage alloc] init]; 53 | } 54 | 55 | - (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType 56 | { 57 | return self.croppedImage; 58 | } 59 | 60 | #pragma mark - Image Generation - 61 | - (id)item 62 | { 63 | //If the user didn't touch the image, just forward along the original 64 | if (self.angle == 0 && CGRectEqualToRect(self.cropFrame, (CGRect){CGPointZero, self.image.size})) { 65 | self.croppedImage = self.image; 66 | return self.croppedImage; 67 | } 68 | 69 | UIImage *image = [self.image croppedImageWithFrame:self.cropFrame angle:self.angle]; 70 | self.croppedImage = image; 71 | return self.croppedImage; 72 | } 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /PureCamera/TOCropOverlayView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TOCropOverlayView.h 3 | // 4 | // Copyright 2015 Timothy Oliver. All rights reserved. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | #import 24 | 25 | @interface TOCropOverlayView : UIView 26 | 27 | @property (nonatomic, assign) BOOL gridHidden; 28 | 29 | /** 30 | Shows and hides the interior grid lines 31 | */ 32 | - (void)setGridHidden:(BOOL)hidden animated:(BOOL)animated; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /PureCamera/TOCropOverlayView.m: -------------------------------------------------------------------------------- 1 | // 2 | // TOCropOverlayView.m 3 | // 4 | // Copyright 2015 Timothy Oliver. All rights reserved. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | #import "TOCropOverlayView.h" 24 | 25 | static const CGFloat kTOCropOverLayerCornerWidth = 20.0f; 26 | 27 | @interface TOCropOverlayView () 28 | 29 | @property (nonatomic, strong) NSArray *horizontalGridLines; 30 | @property (nonatomic, strong) NSArray *verticalGridLines; 31 | 32 | @property (nonatomic, strong) NSArray *outerLineViews; //top, right, bottom, left 33 | 34 | @property (nonatomic, strong) NSArray *topLeftLineViews; //vertical, horizontal 35 | @property (nonatomic, strong) NSArray *bottomLeftLineViews; 36 | @property (nonatomic, strong) NSArray *bottomRightLineViews; 37 | @property (nonatomic, strong) NSArray *topRightLineViews; 38 | 39 | - (void)setup; 40 | - (void)layoutLines; 41 | 42 | @end 43 | 44 | @implementation TOCropOverlayView 45 | 46 | - (instancetype)initWithFrame:(CGRect)frame 47 | { 48 | if (self = [super initWithFrame:frame]) { 49 | self.clipsToBounds = NO; 50 | [self setup]; 51 | } 52 | 53 | return self; 54 | } 55 | 56 | - (void)setup 57 | { 58 | UIView *(^newLineView)(void) = ^UIView *(void){ 59 | UIView *newLine = [[UIView alloc] initWithFrame:CGRectZero]; 60 | newLine.backgroundColor = [UIColor whiteColor]; 61 | [self addSubview:newLine]; 62 | return newLine; 63 | }; 64 | 65 | _outerLineViews = @[newLineView(), newLineView(), newLineView(), newLineView()]; 66 | 67 | _topLeftLineViews = @[newLineView(), newLineView()]; 68 | _bottomLeftLineViews = @[newLineView(), newLineView()]; 69 | _topRightLineViews = @[newLineView(), newLineView()]; 70 | _bottomRightLineViews = @[newLineView(), newLineView()]; 71 | 72 | _horizontalGridLines = @[newLineView(), newLineView()]; 73 | _verticalGridLines = @[newLineView(), newLineView()]; 74 | } 75 | 76 | - (void)setFrame:(CGRect)frame 77 | { 78 | [super setFrame:frame]; 79 | 80 | if (_outerLineViews) 81 | [self layoutLines]; 82 | } 83 | 84 | - (void)didMoveToSuperview 85 | { 86 | [super didMoveToSuperview]; 87 | 88 | if (_outerLineViews) 89 | [self layoutLines]; 90 | } 91 | 92 | - (void)layoutLines 93 | { 94 | CGSize boundsSize = self.bounds.size; 95 | 96 | //border lines 97 | for (NSInteger i = 0; i < 4; i++) { 98 | UIView *lineView = self.outerLineViews[i]; 99 | 100 | CGRect frame = CGRectZero; 101 | switch (i) { 102 | case 0: frame = (CGRect){0,-1.0f,boundsSize.width+2.0f, 1.0f}; break; //top 103 | case 1: frame = (CGRect){boundsSize.width,0.0f,1.0f,boundsSize.height}; break; //right 104 | case 2: frame = (CGRect){-1.0f,boundsSize.height,boundsSize.width+2.0f,1.0f}; break; //bottom 105 | case 3: frame = (CGRect){-1.0f,0,1.0f,boundsSize.height+1.0f}; break; //left 106 | } 107 | 108 | lineView.frame = frame; 109 | } 110 | 111 | //corner liness 112 | NSArray *cornerLines = @[self.topLeftLineViews, self.topRightLineViews, self.bottomRightLineViews, self.bottomLeftLineViews]; 113 | for (NSInteger i = 0; i < 4; i++) { 114 | NSArray *cornerLine = cornerLines[i]; 115 | 116 | CGRect verticalFrame, horizontalFrame; 117 | switch (i) { 118 | case 0: //top left 119 | verticalFrame = (CGRect){-3.0f,-3.0f,3.0f,kTOCropOverLayerCornerWidth+3.0f}; 120 | horizontalFrame = (CGRect){0,-3.0f,kTOCropOverLayerCornerWidth,3.0f}; 121 | break; 122 | case 1: //top right 123 | verticalFrame = (CGRect){boundsSize.width,-3.0f,3.0f,kTOCropOverLayerCornerWidth+3.0f}; 124 | horizontalFrame = (CGRect){boundsSize.width-kTOCropOverLayerCornerWidth,-3.0f,kTOCropOverLayerCornerWidth,3.0f}; 125 | break; 126 | case 2: //bottom right 127 | verticalFrame = (CGRect){boundsSize.width,boundsSize.height-kTOCropOverLayerCornerWidth,3.0f,kTOCropOverLayerCornerWidth+3.0f}; 128 | horizontalFrame = (CGRect){boundsSize.width-kTOCropOverLayerCornerWidth,boundsSize.height,kTOCropOverLayerCornerWidth,3.0f}; 129 | break; 130 | case 3: //bottom left 131 | verticalFrame = (CGRect){-3.0f,boundsSize.height-kTOCropOverLayerCornerWidth,3.0f,kTOCropOverLayerCornerWidth}; 132 | horizontalFrame = (CGRect){-3.0f,boundsSize.height,kTOCropOverLayerCornerWidth+3.0f,3.0f}; 133 | break; 134 | } 135 | 136 | [cornerLine[0] setFrame:verticalFrame]; 137 | [cornerLine[1] setFrame:horizontalFrame]; 138 | } 139 | 140 | //grid lines - horizontal 141 | CGFloat thickness = 1.0f / [[UIScreen mainScreen] scale]; 142 | NSInteger numberOfLines = self.horizontalGridLines.count; 143 | CGFloat padding = (CGRectGetHeight(self.bounds) - (thickness*numberOfLines)) / (numberOfLines + 1); 144 | for (NSInteger i = 0; i < numberOfLines; i++) { 145 | UIView *lineView = self.horizontalGridLines[i]; 146 | CGRect frame = CGRectZero; 147 | frame.size.height = thickness; 148 | frame.size.width = CGRectGetWidth(self.bounds); 149 | frame.origin.y = (padding * (i+1)) + (thickness * i); 150 | lineView.frame = frame; 151 | } 152 | 153 | //grid lines - vertical 154 | numberOfLines = self.verticalGridLines.count; 155 | padding = (CGRectGetWidth(self.bounds) - (thickness*numberOfLines)) / (numberOfLines + 1); 156 | for (NSInteger i = 0; i < numberOfLines; i++) { 157 | UIView *lineView = self.verticalGridLines[i]; 158 | CGRect frame = CGRectZero; 159 | frame.size.width = thickness; 160 | frame.size.height = CGRectGetHeight(self.bounds); 161 | frame.origin.x = (padding * (i+1)) + (thickness * i); 162 | lineView.frame = frame; 163 | } 164 | } 165 | 166 | - (void)setGridHidden:(BOOL)hidden animated:(BOOL)animated 167 | { 168 | _gridHidden = hidden; 169 | 170 | if (animated == NO) { 171 | for (UIView *lineView in self.horizontalGridLines) { 172 | lineView.alpha = hidden ? 0.0f : 1.0f; 173 | } 174 | 175 | for (UIView *lineView in self.verticalGridLines) { 176 | lineView.alpha = hidden ? 0.0f : 1.0f; 177 | } 178 | 179 | return; 180 | } 181 | 182 | [UIView animateWithDuration:hidden?0.35f:0.2f animations:^{ 183 | for (UIView *lineView in self.horizontalGridLines) 184 | lineView.alpha = hidden ? 0.0f : 1.0f; 185 | 186 | for (UIView *lineView in self.verticalGridLines) 187 | lineView.alpha = hidden ? 0.0f : 1.0f; 188 | }]; 189 | } 190 | 191 | - (void)setGridHidden:(BOOL)gridHidden 192 | { 193 | [self setGridHidden:gridHidden animated:NO]; 194 | } 195 | 196 | @end 197 | -------------------------------------------------------------------------------- /PureCamera/TOCropScrollView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TOCropScrollView 3 | // 4 | // Copyright 2015 Timothy Oliver. All rights reserved. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | #import 24 | 25 | @interface TOCropScrollView : UIScrollView 26 | 27 | @property (nonatomic, copy) void (^touchesBegan)(void); 28 | @property (nonatomic, copy) void (^touchesCancelled)(void); 29 | @property (nonatomic, copy) void (^touchesEnded)(void); 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /PureCamera/TOCropScrollView.m: -------------------------------------------------------------------------------- 1 | // 2 | // TOCropScrollView 3 | // 4 | // Copyright 2015 Timothy Oliver. All rights reserved. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | #import "TOCropScrollView.h" 24 | 25 | @implementation TOCropScrollView 26 | 27 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 28 | { 29 | if (self.touchesBegan) 30 | self.touchesBegan(); 31 | 32 | [super touchesBegan:touches withEvent:event]; 33 | } 34 | 35 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 36 | { 37 | if (self.touchesEnded) 38 | self.touchesEnded(); 39 | 40 | [super touchesEnded:touches withEvent:event]; 41 | } 42 | 43 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 44 | { 45 | if (self.touchesCancelled) 46 | self.touchesCancelled(); 47 | 48 | [super touchesCancelled:touches withEvent:event]; 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /PureCamera/TOCropToolbar.h: -------------------------------------------------------------------------------- 1 | // 2 | // TOCropToolbar.h 3 | // 4 | // Copyright 2015 Timothy Oliver. All rights reserved. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | #import 24 | 25 | @interface TOCropToolbar : UIView 26 | 27 | /* Button feedback handler blocks */ 28 | @property (nonatomic, copy) void (^cancelButtonTapped)(void); 29 | @property (nonatomic, copy) void (^doneButtonTapped)(void); 30 | @property (nonatomic, copy) void (^rotateButtonTapped)(void); 31 | @property (nonatomic, copy) void (^clampButtonTapped)(void); 32 | @property (nonatomic, copy) void (^resetButtonTapped)(void); 33 | 34 | /* Aspect ratio button settings */ 35 | @property (nonatomic, assign) BOOL clampButtonGlowing; 36 | @property (nonatomic, readonly) CGRect clampButtonFrame; 37 | 38 | /* Disable the rotate button */ 39 | @property (nonatomic, assign) BOOL rotateButtonHidden; 40 | 41 | /* Enable the reset button */ 42 | @property (nonatomic, assign) BOOL resetButtonEnabled; 43 | 44 | /* Done button frame for popover controllers */ 45 | @property (nonatomic, readonly) CGRect doneButtonFrame; 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /PureCamera/TOCropToolbar.m: -------------------------------------------------------------------------------- 1 | // 2 | // TOCropToolbar.h 3 | // 4 | // Copyright 2015 Timothy Oliver. All rights reserved. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | #import "TOCropToolbar.h" 24 | 25 | @interface TOCropToolbar() 26 | 27 | @property (nonatomic, strong) UIButton *doneTextButton; 28 | @property (nonatomic, strong) UIButton *doneIconButton; 29 | 30 | @property (nonatomic, strong) UIButton *cancelTextButton; 31 | @property (nonatomic, strong) UIButton *cancelIconButton; 32 | 33 | @property (nonatomic, strong) UIButton *rotateButton; 34 | @property (nonatomic, strong) UIButton *resetButton; 35 | @property (nonatomic, strong) UIButton *clampButton; 36 | 37 | - (void)setup; 38 | - (void)buttonTapped:(id)button; 39 | 40 | + (UIImage *)doneImage; 41 | + (UIImage *)cancelImage; 42 | + (UIImage *)resetImage; 43 | + (UIImage *)rotateImage; 44 | + (UIImage *)clampImage; 45 | 46 | @end 47 | 48 | @implementation TOCropToolbar 49 | 50 | - (instancetype)initWithFrame:(CGRect)frame 51 | { 52 | if (self = [super initWithFrame:frame]) { 53 | [self setup]; 54 | } 55 | 56 | return self; 57 | } 58 | 59 | - (void)setup { 60 | self.backgroundColor = [UIColor colorWithWhite:0.12f alpha:1.0f]; 61 | 62 | _doneTextButton = [UIButton buttonWithType:UIButtonTypeSystem]; 63 | _doneTextButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; 64 | [_doneTextButton setTitle:NSLocalizedStringFromTableInBundle(@"完成", 65 | @"TOCropViewControllerLocalizable",[NSBundle bundleForClass:[self class]], 66 | nil)forState:UIControlStateNormal]; 67 | [_doneTextButton setTitleColor:[UIColor colorWithRed:1.0f green:0.8f blue:0.0f alpha:1.0f] forState:UIControlStateNormal]; 68 | [_doneTextButton.titleLabel setFont:[UIFont systemFontOfSize:17.0f]]; 69 | [_doneTextButton addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside]; 70 | [self addSubview:_doneTextButton]; 71 | 72 | _doneIconButton = [UIButton buttonWithType:UIButtonTypeSystem]; 73 | [_doneIconButton setImage:[TOCropToolbar doneImage] forState:UIControlStateNormal]; 74 | [_doneIconButton setTintColor:[UIColor colorWithRed:1.0f green:0.8f blue:0.0f alpha:1.0f]]; 75 | [_doneIconButton addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside]; 76 | [self addSubview:_doneIconButton]; 77 | 78 | _cancelTextButton = [UIButton buttonWithType:UIButtonTypeSystem]; 79 | _cancelTextButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight; 80 | [_cancelTextButton setTitle:NSLocalizedStringFromTableInBundle(@"取消", 81 | @"TOCropViewControllerLocalizable", 82 | [NSBundle bundleForClass:[self class]], 83 | nil) 84 | forState:UIControlStateNormal]; 85 | [_cancelTextButton.titleLabel setFont:[UIFont systemFontOfSize:17.0f]]; 86 | [_cancelTextButton addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside]; 87 | [self addSubview:_cancelTextButton]; 88 | 89 | _cancelIconButton = [UIButton buttonWithType:UIButtonTypeSystem]; 90 | [_cancelIconButton setImage:[TOCropToolbar cancelImage] forState:UIControlStateNormal]; 91 | [_cancelIconButton addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside]; 92 | [self addSubview:_cancelIconButton]; 93 | 94 | _clampButton = [UIButton buttonWithType:UIButtonTypeSystem]; 95 | _clampButton.contentMode = UIViewContentModeCenter; 96 | _clampButton.tintColor = [UIColor whiteColor]; 97 | [_clampButton setImage:[TOCropToolbar clampImage] forState:UIControlStateNormal]; 98 | [_clampButton addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside]; 99 | [self addSubview:_clampButton]; 100 | 101 | _rotateButton = [UIButton buttonWithType:UIButtonTypeSystem]; 102 | _rotateButton.contentMode = UIViewContentModeCenter; 103 | _rotateButton.tintColor = [UIColor whiteColor]; 104 | [_rotateButton setImage:[TOCropToolbar rotateImage] forState:UIControlStateNormal]; 105 | [_rotateButton addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside]; 106 | [self addSubview:_rotateButton]; 107 | 108 | _resetButton = [UIButton buttonWithType:UIButtonTypeSystem]; 109 | _resetButton.contentMode = UIViewContentModeCenter; 110 | _resetButton.tintColor = [UIColor whiteColor]; 111 | _resetButton.enabled = NO; 112 | [_resetButton setImage:[TOCropToolbar resetImage] forState:UIControlStateNormal]; 113 | [_resetButton addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside]; 114 | [self addSubview:_resetButton]; 115 | } 116 | 117 | - (void)layoutSubviews 118 | { 119 | [super layoutSubviews]; 120 | 121 | BOOL verticalLayout = (CGRectGetWidth(self.bounds) < CGRectGetHeight(self.bounds)); 122 | CGSize boundsSize = self.bounds.size; 123 | 124 | self.cancelIconButton.hidden = (!verticalLayout); 125 | self.cancelTextButton.hidden = (verticalLayout); 126 | self.doneIconButton.hidden = (!verticalLayout); 127 | self.doneTextButton.hidden = (verticalLayout); 128 | 129 | self.rotateButton.hidden = self.rotateButtonHidden; 130 | 131 | if (verticalLayout == NO) { 132 | CGRect frame = CGRectZero; 133 | frame.size.height = 44.0f; 134 | frame.size.width = [self.cancelTextButton.titleLabel.text sizeWithAttributes:@{NSFontAttributeName:self.cancelTextButton.titleLabel.font}].width + 10; 135 | self.cancelTextButton.frame = frame; 136 | 137 | frame.size.width = [self.doneTextButton.titleLabel.text sizeWithAttributes:@{NSFontAttributeName:self.doneTextButton.titleLabel.font}].width + 10; 138 | frame.origin.x = boundsSize.width - CGRectGetWidth(frame); 139 | self.doneTextButton.frame = frame; 140 | 141 | CGRect containerRect = (CGRect){0,0,165.0f,44.0f}; 142 | containerRect.origin.x = (CGRectGetWidth(self.bounds) - (CGRectGetWidth(containerRect))) * 0.5f; 143 | 144 | CGRect buttonFrame = (CGRect){0,0,44.0f,44.0f}; 145 | 146 | if (self.rotateButtonHidden) { 147 | buttonFrame.origin.x = CGRectGetMinX(containerRect); 148 | self.resetButton.frame = buttonFrame; 149 | } 150 | else { 151 | buttonFrame.origin.x = CGRectGetMinX(containerRect); 152 | self.rotateButton.frame = buttonFrame; 153 | 154 | buttonFrame.origin.x = CGRectGetMidX(containerRect) - 22.0f; 155 | self.resetButton.frame = buttonFrame; 156 | } 157 | 158 | buttonFrame.origin.x = CGRectGetMaxX(containerRect) - 44.0f; 159 | self.clampButton.frame = buttonFrame; 160 | } 161 | else { 162 | CGRect frame = CGRectZero; 163 | frame.size.height = 44.0f; 164 | frame.size.width = 44.0f; 165 | frame.origin.y = CGRectGetHeight(self.bounds) - 44.0f; 166 | self.cancelIconButton.frame = frame; 167 | 168 | frame.origin.y = 0.0f; 169 | frame.size.width = 44.0f; 170 | frame.size.height = 44.0f; 171 | self.doneIconButton.frame = frame; 172 | 173 | CGRect containerRect = (CGRect){0,0,44.0f,165.0f}; 174 | containerRect.origin.y = (CGRectGetHeight(self.bounds) - (CGRectGetHeight(containerRect))) * 0.5f; 175 | 176 | CGRect buttonFrame = (CGRect){0,0,44.0f,44.0f}; 177 | 178 | if (self.rotateButtonHidden) { 179 | buttonFrame.origin.y = CGRectGetMinY(containerRect); 180 | self.resetButton.frame = buttonFrame; 181 | } 182 | else { 183 | buttonFrame.origin.y = CGRectGetMinY(containerRect); 184 | self.rotateButton.frame = buttonFrame; 185 | 186 | buttonFrame.origin.y = CGRectGetMidY(containerRect) - 22.0f; 187 | self.resetButton.frame = buttonFrame; 188 | } 189 | 190 | buttonFrame.origin.y = CGRectGetMaxY(containerRect) - 44.0f; 191 | self.clampButton.frame = buttonFrame; 192 | } 193 | } 194 | 195 | - (void)buttonTapped:(id)button 196 | { 197 | if (button == self.cancelTextButton || button == self.cancelIconButton) { 198 | if (self.cancelButtonTapped) 199 | self.cancelButtonTapped(); 200 | } 201 | else if (button == self.doneTextButton || button == self.doneIconButton) { 202 | if (self.doneButtonTapped) 203 | self.doneButtonTapped(); 204 | } 205 | else if (button == self.resetButton && self.resetButtonTapped) { 206 | self.resetButtonTapped(); 207 | } 208 | else if (button == self.rotateButton && self.rotateButtonTapped) { 209 | self.rotateButtonTapped(); 210 | } 211 | else if (button == self.clampButton && self.clampButtonTapped) { 212 | self.clampButtonTapped(); 213 | return; 214 | } 215 | } 216 | 217 | - (CGRect)clampButtonFrame 218 | { 219 | return self.clampButton.frame; 220 | } 221 | 222 | - (void)setClampButtonGlowing:(BOOL)clampButtonGlowing 223 | { 224 | if (_clampButtonGlowing == clampButtonGlowing) 225 | return; 226 | 227 | _clampButtonGlowing = clampButtonGlowing; 228 | 229 | if (_clampButtonGlowing) 230 | self.clampButton.tintColor = nil; 231 | else 232 | self.clampButton.tintColor = [UIColor whiteColor]; 233 | } 234 | 235 | - (void)setRotateButtonHidden:(BOOL)rotateButtonHidden 236 | { 237 | if (_rotateButtonHidden == rotateButtonHidden) 238 | return; 239 | 240 | _rotateButtonHidden = rotateButtonHidden; 241 | [self setNeedsLayout]; 242 | } 243 | 244 | - (BOOL)resetButtonEnabled 245 | { 246 | return self.resetButton.enabled; 247 | } 248 | 249 | - (void)setResetButtonEnabled:(BOOL)resetButtonEnabled 250 | { 251 | self.resetButton.enabled = resetButtonEnabled; 252 | } 253 | 254 | - (CGRect)doneButtonFrame 255 | { 256 | if (self.doneIconButton.hidden == NO) 257 | return self.doneIconButton.frame; 258 | 259 | return self.doneTextButton.frame; 260 | } 261 | 262 | #pragma mark - Image Generation - 263 | + (UIImage *)doneImage 264 | { 265 | UIImage *doneImage = nil; 266 | 267 | UIGraphicsBeginImageContextWithOptions((CGSize){17,14}, NO, 0.0f); 268 | { 269 | //// Rectangle Drawing 270 | UIBezierPath* rectanglePath = UIBezierPath.bezierPath; 271 | [rectanglePath moveToPoint: CGPointMake(1, 7)]; 272 | [rectanglePath addLineToPoint: CGPointMake(6, 12)]; 273 | [rectanglePath addLineToPoint: CGPointMake(16, 1)]; 274 | [UIColor.whiteColor setStroke]; 275 | rectanglePath.lineWidth = 2; 276 | [rectanglePath stroke]; 277 | 278 | 279 | doneImage = UIGraphicsGetImageFromCurrentImageContext(); 280 | } 281 | UIGraphicsEndImageContext(); 282 | 283 | return doneImage; 284 | } 285 | 286 | + (UIImage *)cancelImage 287 | { 288 | UIImage *cancelImage = nil; 289 | 290 | UIGraphicsBeginImageContextWithOptions((CGSize){16,16}, NO, 0.0f); 291 | { 292 | UIBezierPath* bezierPath = UIBezierPath.bezierPath; 293 | [bezierPath moveToPoint: CGPointMake(15, 15)]; 294 | [bezierPath addLineToPoint: CGPointMake(1, 1)]; 295 | [UIColor.whiteColor setStroke]; 296 | bezierPath.lineWidth = 2; 297 | [bezierPath stroke]; 298 | 299 | 300 | //// Bezier 2 Drawing 301 | UIBezierPath* bezier2Path = UIBezierPath.bezierPath; 302 | [bezier2Path moveToPoint: CGPointMake(1, 15)]; 303 | [bezier2Path addLineToPoint: CGPointMake(15, 1)]; 304 | [UIColor.whiteColor setStroke]; 305 | bezier2Path.lineWidth = 2; 306 | [bezier2Path stroke]; 307 | 308 | cancelImage = UIGraphicsGetImageFromCurrentImageContext(); 309 | } 310 | UIGraphicsEndImageContext(); 311 | 312 | return cancelImage; 313 | } 314 | 315 | + (UIImage *)rotateImage 316 | { 317 | UIImage *rotateImage = nil; 318 | 319 | UIGraphicsBeginImageContextWithOptions((CGSize){18,21}, NO, 0.0f); 320 | { 321 | //// Rectangle 2 Drawing 322 | UIBezierPath* rectangle2Path = [UIBezierPath bezierPathWithRect: CGRectMake(0, 9, 12, 12)]; 323 | [UIColor.whiteColor setFill]; 324 | [rectangle2Path fill]; 325 | 326 | 327 | //// Rectangle 3 Drawing 328 | UIBezierPath* rectangle3Path = UIBezierPath.bezierPath; 329 | [rectangle3Path moveToPoint: CGPointMake(5, 3)]; 330 | [rectangle3Path addLineToPoint: CGPointMake(10, 6)]; 331 | [rectangle3Path addLineToPoint: CGPointMake(10, 0)]; 332 | [rectangle3Path addLineToPoint: CGPointMake(5, 3)]; 333 | [rectangle3Path closePath]; 334 | [UIColor.whiteColor setFill]; 335 | [rectangle3Path fill]; 336 | 337 | 338 | //// Bezier Drawing 339 | UIBezierPath* bezierPath = UIBezierPath.bezierPath; 340 | [bezierPath moveToPoint: CGPointMake(10, 3)]; 341 | [bezierPath addCurveToPoint: CGPointMake(17.5, 11) controlPoint1: CGPointMake(15, 3) controlPoint2: CGPointMake(17.5, 5.91)]; 342 | [UIColor.whiteColor setStroke]; 343 | bezierPath.lineWidth = 1; 344 | [bezierPath stroke]; 345 | rotateImage = UIGraphicsGetImageFromCurrentImageContext(); 346 | } 347 | UIGraphicsEndImageContext(); 348 | 349 | return rotateImage; 350 | } 351 | 352 | + (UIImage *)resetImage 353 | { 354 | UIImage *resetImage = nil; 355 | 356 | UIGraphicsBeginImageContextWithOptions((CGSize){22,18}, NO, 0.0f); 357 | { 358 | 359 | //// Bezier 2 Drawing 360 | UIBezierPath* bezier2Path = UIBezierPath.bezierPath; 361 | [bezier2Path moveToPoint: CGPointMake(22, 9)]; 362 | [bezier2Path addCurveToPoint: CGPointMake(13, 18) controlPoint1: CGPointMake(22, 13.97) controlPoint2: CGPointMake(17.97, 18)]; 363 | [bezier2Path addCurveToPoint: CGPointMake(13, 16) controlPoint1: CGPointMake(13, 17.35) controlPoint2: CGPointMake(13, 16.68)]; 364 | [bezier2Path addCurveToPoint: CGPointMake(20, 9) controlPoint1: CGPointMake(16.87, 16) controlPoint2: CGPointMake(20, 12.87)]; 365 | [bezier2Path addCurveToPoint: CGPointMake(13, 2) controlPoint1: CGPointMake(20, 5.13) controlPoint2: CGPointMake(16.87, 2)]; 366 | [bezier2Path addCurveToPoint: CGPointMake(6.55, 6.27) controlPoint1: CGPointMake(10.1, 2) controlPoint2: CGPointMake(7.62, 3.76)]; 367 | [bezier2Path addCurveToPoint: CGPointMake(6, 9) controlPoint1: CGPointMake(6.2, 7.11) controlPoint2: CGPointMake(6, 8.03)]; 368 | [bezier2Path addLineToPoint: CGPointMake(4, 9)]; 369 | [bezier2Path addCurveToPoint: CGPointMake(4.65, 5.63) controlPoint1: CGPointMake(4, 7.81) controlPoint2: CGPointMake(4.23, 6.67)]; 370 | [bezier2Path addCurveToPoint: CGPointMake(7.65, 1.76) controlPoint1: CGPointMake(5.28, 4.08) controlPoint2: CGPointMake(6.32, 2.74)]; 371 | [bezier2Path addCurveToPoint: CGPointMake(13, 0) controlPoint1: CGPointMake(9.15, 0.65) controlPoint2: CGPointMake(11, 0)]; 372 | [bezier2Path addCurveToPoint: CGPointMake(22, 9) controlPoint1: CGPointMake(17.97, 0) controlPoint2: CGPointMake(22, 4.03)]; 373 | [bezier2Path closePath]; 374 | [UIColor.whiteColor setFill]; 375 | [bezier2Path fill]; 376 | 377 | 378 | //// Polygon Drawing 379 | UIBezierPath* polygonPath = UIBezierPath.bezierPath; 380 | [polygonPath moveToPoint: CGPointMake(5, 15)]; 381 | [polygonPath addLineToPoint: CGPointMake(10, 9)]; 382 | [polygonPath addLineToPoint: CGPointMake(0, 9)]; 383 | [polygonPath addLineToPoint: CGPointMake(5, 15)]; 384 | [polygonPath closePath]; 385 | [UIColor.whiteColor setFill]; 386 | [polygonPath fill]; 387 | 388 | 389 | resetImage = UIGraphicsGetImageFromCurrentImageContext(); 390 | } 391 | 392 | return resetImage; 393 | } 394 | 395 | + (UIImage *)clampImage 396 | { 397 | UIImage *clampImage = nil; 398 | 399 | UIGraphicsBeginImageContextWithOptions((CGSize){22,16}, NO, 0.0f); 400 | { 401 | //// Color Declarations 402 | UIColor* outerBox = [UIColor colorWithRed: 1 green: 1 blue: 1 alpha: 0.553]; 403 | UIColor* innerBox = [UIColor colorWithRed: 1 green: 1 blue: 1 alpha: 0.773]; 404 | 405 | //// Rectangle Drawing 406 | UIBezierPath* rectanglePath = [UIBezierPath bezierPathWithRect: CGRectMake(0, 3, 13, 13)]; 407 | [UIColor.whiteColor setFill]; 408 | [rectanglePath fill]; 409 | 410 | 411 | //// Outer 412 | { 413 | //// Top Drawing 414 | UIBezierPath* topPath = [UIBezierPath bezierPathWithRect: CGRectMake(0, 0, 22, 2)]; 415 | [outerBox setFill]; 416 | [topPath fill]; 417 | 418 | 419 | //// Side Drawing 420 | UIBezierPath* sidePath = [UIBezierPath bezierPathWithRect: CGRectMake(19, 2, 3, 14)]; 421 | [outerBox setFill]; 422 | [sidePath fill]; 423 | } 424 | 425 | 426 | //// Rectangle 2 Drawing 427 | UIBezierPath* rectangle2Path = [UIBezierPath bezierPathWithRect: CGRectMake(14, 3, 4, 13)]; 428 | [innerBox setFill]; 429 | [rectangle2Path fill]; 430 | 431 | 432 | clampImage = UIGraphicsGetImageFromCurrentImageContext(); 433 | } 434 | UIGraphicsEndImageContext(); 435 | 436 | return clampImage; 437 | } 438 | 439 | @end 440 | -------------------------------------------------------------------------------- /PureCamera/TOCropView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TOCropView.h 3 | // 4 | // Copyright 2015 Timothy Oliver. All rights reserved. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | #import 24 | 25 | @class TOCropView; 26 | 27 | @protocol TOCropViewDelegate 28 | 29 | - (void)cropViewDidBecomeResettable:(TOCropView *)cropView; 30 | - (void)cropViewDidBecomeNonResettable:(TOCropView *)cropView; 31 | 32 | @end 33 | 34 | @interface TOCropView : UIView 35 | 36 | /** 37 | The image that the crop view is displaying. This cannot be changed once the crop view is instantiated. 38 | */ 39 | @property (nonatomic, strong, readonly) UIImage *image; 40 | 41 | /** 42 | A delegate object that receives notifications from the crop view 43 | */ 44 | @property (nonatomic, weak) id delegate; 45 | 46 | /** 47 | Whether the user has manipulated the crop view to the point where it can be reset 48 | */ 49 | @property (nonatomic, readonly) BOOL canReset; 50 | 51 | /** 52 | The frame of the cropping box on the crop view 53 | */ 54 | @property (nonatomic, readonly) CGRect cropBoxFrame; 55 | 56 | /** 57 | The frame of the entire image in the backing scroll view 58 | */ 59 | @property (nonatomic, readonly) CGRect imageViewFrame; 60 | 61 | /** 62 | Inset the workable region of the crop view in case in order to make space for accessory views 63 | */ 64 | @property (nonatomic, assign) UIEdgeInsets cropRegionInsets; 65 | 66 | /** 67 | Disable the dynamic translucency in order to smoothly relayout the view 68 | */ 69 | @property (nonatomic, assign) BOOL simpleMode; 70 | 71 | /** 72 | When the cropping box is locked to its current size 73 | */ 74 | @property (nonatomic, assign) BOOL aspectLockEnabled; 75 | 76 | /** 77 | True when the height of the crop box is bigger than the width 78 | */ 79 | @property (nonatomic, readonly) BOOL cropBoxAspectRatioIsPortrait; 80 | 81 | /** 82 | The rotation angle of the crop view (Will always be negative as it rotates in a counter-clockwise direction) 83 | */ 84 | @property (nonatomic, assign, readonly) NSInteger angle; 85 | 86 | /** 87 | Hide all of the crop elements for transition animations 88 | */ 89 | @property (nonatomic, assign) BOOL croppingViewsHidden; 90 | 91 | /** 92 | In relation to the coordinate space of the image, the frame that the crop view is focussing on 93 | */ 94 | @property (nonatomic, readonly) CGRect croppedImageFrame; 95 | 96 | /** 97 | Set the grid overlay graphic to be hidden 98 | */ 99 | @property (nonatomic, assign) BOOL gridOverlayHidden; 100 | 101 | /** 102 | Create a new instance of the crop view with the supplied image 103 | */ 104 | - (instancetype)initWithImage:(UIImage *)image; 105 | 106 | /** 107 | When performing large size transitions (eg, orientation rotation), 108 | set simple mode to YES to temporarily graphically heavy effects like translucency. 109 | 110 | @param simpleMode Whether simple mode is enabled or not 111 | 112 | */ 113 | - (void)setSimpleMode:(BOOL)simpleMode animated:(BOOL)animated; 114 | 115 | /** 116 | When performing a screen rotation that will change the size of the scroll view, this takes 117 | a snapshot of all of the scroll view data before it gets manipulated by iOS. 118 | Please call this in your view controller, before the rotation animation block is committed. 119 | */ 120 | - (void)prepareforRotation; 121 | 122 | /** 123 | Performs the realignment of the crop view while the screen is rotating. 124 | Please call this inside your view controller's screen rotation animation block. 125 | */ 126 | - (void)performRelayoutForRotation; 127 | 128 | /** 129 | Reset the crop box and zoom scale back to the initial layout 130 | 131 | @param animated The reset is animated 132 | */ 133 | - (void)resetLayoutToDefaultAnimated:(BOOL)animated; 134 | 135 | /** 136 | Enables an aspect ratio lock where the crop box will always scale at a specific ratio. 137 | 138 | @param aspectRatio The aspect ratio (For example 16:9 is 16.0f/9.0f). Specify 0.0f to lock to the image's original aspect ratio 139 | @param animated Whether the locking effect is animated 140 | */ 141 | - (void)setAspectLockEnabledWithAspectRatio:(CGSize)aspectRatio animated:(BOOL)animated; 142 | 143 | /** 144 | Rotates the entire canvas to a 90-degree angle 145 | 146 | @param angle The angle in which to rotate (May be 0, 90, 180, 270) 147 | @param animated Whether the transition is animated 148 | */ 149 | - (void)rotateImageNinetyDegreesAnimated:(BOOL)animated; 150 | 151 | /** 152 | Animate the grid overlay graphic to be visible 153 | */ 154 | - (void)setGridOverlayHidden:(BOOL)gridOverlayHidden animated:(BOOL)animated; 155 | 156 | /** 157 | Animate the cropping component views to become visible 158 | */ 159 | - (void)setCroppingViewsHidden:(BOOL)hidden animated:(BOOL)animated; 160 | 161 | 162 | @end 163 | -------------------------------------------------------------------------------- /PureCamera/TOCropViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TOCropViewController.h 3 | // 4 | // Copyright 2015 Timothy Oliver. All rights reserved. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | #import 24 | @class TOCropViewController; 25 | 26 | 27 | ///------------------------------------------------ 28 | /// @name Delegate 29 | ///------------------------------------------------ 30 | 31 | @protocol TOCropViewControllerDelegate 32 | @optional 33 | 34 | /** 35 | Called when the user has committed the crop action, and provides just the cropping rectangle 36 | 37 | @param image The newly cropped image. 38 | @param cropRect A rectangle indicating the crop region of the image the user chose (In the original image's local co-ordinate space) 39 | */ 40 | - (void)cropViewController:(TOCropViewController *)cropViewController didCropImageToRect:(CGRect)cropRect angle:(NSInteger)angle; 41 | 42 | /** 43 | Called when the user has committed the crop action, and provides both the original image with crop co-ordinates. 44 | 45 | @param image The newly cropped image. 46 | @param cropRect A rectangle indicating the crop region of the image the user chose (In the original image's local co-ordinate space) 47 | */ 48 | - (void)cropViewController:(TOCropViewController *)cropViewController didCropToImage:(UIImage *)image withRect:(CGRect)cropRect angle:(NSInteger)angle; 49 | 50 | /** 51 | If implemented, when the user hits cancel, or completes a UIActivityViewController operation, this delegate will be called, 52 | giving you a chance to manually dismiss the view controller 53 | 54 | */ 55 | - (void)cropViewController:(TOCropViewController *)cropViewController didFinishCancelled:(BOOL)cancelled; 56 | 57 | @end 58 | 59 | 60 | typedef enum : NSInteger { 61 | TOCropViewControllerAspectRatioOriginal = 0, 62 | TOCropViewControllerAspectRatioSquare, 63 | TOCropViewControllerAspectRatio1x2, 64 | TOCropViewControllerAspectRatio3x2, 65 | TOCropViewControllerAspectRatio5x3, 66 | TOCropViewControllerAspectRatio4x3, 67 | TOCropViewControllerAspectRatio5x4, 68 | TOCropViewControllerAspectRatio7x5, 69 | TOCropViewControllerAspectRatio16x9, 70 | } TOCropViewControllerAspectRatio; 71 | 72 | 73 | 74 | @interface TOCropViewController : UIViewController 75 | 76 | //typedef enum(NSInteger, TOCropViewControllerAspectRatio) { 77 | // TOCropViewControllerAspectRatioOriginal, 78 | // TOCropViewControllerAspectRatioSquare, 79 | // TOCropViewControllerAspectRatio1x2, 80 | // TOCropViewControllerAspectRatio3x2, 81 | // TOCropViewControllerAspectRatio5x3, 82 | // TOCropViewControllerAspectRatio4x3, 83 | // TOCropViewControllerAspectRatio5x4, 84 | // TOCropViewControllerAspectRatio7x5, 85 | // TOCropViewControllerAspectRatio16x9 86 | //}; 87 | 88 | 89 | /** 90 | The original, uncropped image that was passed to this controller. 91 | */ 92 | @property (nonatomic, readonly) UIImage *image; 93 | 94 | /** 95 | The view controller's delegate that will return the resulting cropped image, as well as crop information 96 | */ 97 | @property (nonatomic, weak) id delegate; 98 | 99 | /** 100 | If true, when the user hits 'Done', a UIActivityController will appear before the view controller ends 101 | */ 102 | @property (nonatomic, assign) BOOL showActivitySheetOnDone; 103 | 104 | /** 105 | If performing a transition animation, this block can be used to set up any view states just before the animation begins 106 | */ 107 | @property (nonatomic, copy) void (^prepareForTransitionHandler)(void); 108 | 109 | /** 110 | If `showActivitySheetOnDone` is true, then these activity items will be supplied to that UIActivityViewController 111 | in addition to the `TOActivityCroppedImageProvider` object. 112 | */ 113 | @property (nonatomic, strong) NSArray *activityItems; 114 | 115 | /** 116 | If `showActivitySheetOnDone` is true, then you may specify any custom activities your app implements in this array. 117 | If your activity requires access to the cropping information, it can be accessed in the supplied `TOActivityCroppedImageProvider` object 118 | */ 119 | @property (nonatomic, strong) NSArray *applicationActivities; 120 | 121 | /** 122 | If `showActivitySheetOnDone` is true, then you may expliclty set activities that won't appear in the share sheet here. 123 | */ 124 | @property (nonatomic, strong) NSArray *excludedActivityTypes; 125 | 126 | ///------------------------------------------------ 127 | /// @name Object Creation 128 | ///------------------------------------------------ 129 | 130 | /** 131 | Creates a new instance of a crop view controller with the supplied image 132 | 133 | @param image The image that will be used to crop. 134 | */ 135 | - (instancetype)initWithImage:(UIImage *)image aspectRatioStle:(TOCropViewControllerAspectRatio)style; 136 | 137 | /** 138 | Play a custom animation of the target image zooming to its position in the crop controller while the background fades in. 139 | If any view configurations need to be done before the animation starts, please do them in `prepareForTransitionHandler` 140 | 141 | @param viewController The parent controller that this view controller would be presenting from. 142 | @param frame In the screen's coordinate space, the frame from which the image should animate from. 143 | @param completion A block that is called once the transition animation is completed. 144 | */ 145 | - (void)presentAnimatedFromParentViewController:(UIViewController *)viewController fromFrame:(CGRect)frame completion:(void (^)(void))completion; 146 | 147 | /** 148 | Play a custom animation of the supplied cropped image zooming out from the cropped frame to the specified frame as the rest of the content fades out. 149 | If any view configurations need to be done before the animation starts, please do them in `prepareForTransitionHandler` 150 | 151 | @param viewController The parent controller that this view controller would be presenting from. 152 | @param frame The target frame that the image will animate to 153 | @param completion A block that is called once the transition animation is completed. 154 | */ 155 | - (void)dismissAnimatedFromParentViewController:(UIViewController *)viewController withCroppedImage:(UIImage *)image toFrame:(CGRect)frame completion:(void (^)(void))completion; 156 | 157 | /** 158 | Play a custom animation of the supplied cropped image zooming out from the cropped frame to the specified frame as the rest of the content fades out. 159 | If any view configurations need to be done before the animation starts, please do them in `prepareForTransitionHandler` 160 | 161 | @param viewController The parent controller that this view controller would be presenting from. 162 | @param frame The target frame that the image will animate to 163 | @param completion A block that is called once the transition animation is completed. 164 | */ 165 | - (void)dismissAnimatedFromParentViewController:(UIViewController *)viewController toFrame:(CGRect)frame completion:(void (^)(void))completion; 166 | 167 | @end 168 | 169 | -------------------------------------------------------------------------------- /PureCamera/TOCropViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TOCropViewController.h 3 | // 4 | // Copyright 2015 Timothy Oliver. All rights reserved. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | #import "TOCropViewController.h" 24 | #import "TOCropView.h" 25 | 26 | #import "TOCropToolbar.h" 27 | #import "TOCropViewControllerTransitioning.h" 28 | #import "TOActivityCroppedImageProvider.h" 29 | #import "UIImage+CropRotate.h" 30 | #import "TOCroppedImageAttributes.h" 31 | 32 | 33 | 34 | @interface TOCropViewController () 35 | @property (nonatomic, strong) TOCropView *cropView; 36 | 37 | @property (nonatomic, readwrite) UIImage *image; 38 | @property (nonatomic, strong) TOCropToolbar *toolbar; 39 | @property (nonatomic, strong) UIView *snapshotView; 40 | @property (nonatomic, strong) TOCropViewControllerTransitioning *transitionController; 41 | @property (nonatomic, assign) BOOL inTransition; 42 | @property (nonatomic, assign) TOCropViewControllerAspectRatio aspectRatioStle; 43 | 44 | 45 | #pragma clang diagnostic push 46 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 47 | @property (nonatomic, strong) UIPopoverController *activityPopoverController; 48 | #pragma clang diagnostic pop 49 | 50 | /* Button callback */ 51 | - (void)cancelButtonTapped; 52 | - (void)doneButtonTapped; 53 | - (void)showAspectRatioDialog; 54 | - (void)resetCropViewLayout; 55 | - (void)rotateCropView; 56 | 57 | /* View layout */ 58 | - (CGRect)frameForToolBarWithVerticalLayout:(BOOL)verticalLayout; 59 | 60 | @end 61 | 62 | @implementation TOCropViewController 63 | 64 | - (instancetype)initWithImage:(UIImage *)image aspectRatioStle:(TOCropViewControllerAspectRatio)aspectRatioStle 65 | { 66 | self = [super init]; 67 | if (self) { 68 | 69 | self.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; 70 | self.modalPresentationStyle = UIModalPresentationFullScreen; 71 | 72 | _transitionController = [[TOCropViewControllerTransitioning alloc] init]; 73 | _image = image; 74 | self.aspectRatioStle = aspectRatioStle; 75 | 76 | } 77 | 78 | return self; 79 | } 80 | 81 | - (void)viewDidLoad 82 | { 83 | [super viewDidLoad]; 84 | 85 | BOOL landscapeLayout = CGRectGetWidth(self.view.frame) > CGRectGetHeight(self.view.frame); 86 | self.cropView = [[TOCropView alloc] initWithImage:self.image]; 87 | self.cropView.frame = (CGRect){(landscapeLayout ? 44.0f : 0.0f),0,(CGRectGetWidth(self.view.bounds) - (landscapeLayout ? 44.0f : 0.0f)), (CGRectGetHeight(self.view.bounds)-(landscapeLayout ? 0.0f : 44.0f)) }; 88 | self.cropView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 89 | self.cropView.delegate = self; 90 | [self.view addSubview:self.cropView]; 91 | CGSize aspectRatio = CGSizeZero; 92 | // aspectRatio = CGSizeMake(1.0f, 2.0f); 93 | aspectRatio = [self convertAspectRatioStyleToRatio:self.aspectRatioStle]; 94 | 95 | [self.cropView setAspectLockEnabledWithAspectRatio:aspectRatio animated:false]; 96 | 97 | self.toolbar = [[TOCropToolbar alloc] initWithFrame:CGRectZero]; 98 | self.toolbar.frame = [self frameForToolBarWithVerticalLayout:CGRectGetWidth(self.view.bounds) < CGRectGetHeight(self.view.bounds)]; 99 | [self.view addSubview:self.toolbar]; 100 | 101 | __weak typeof(self) weakSelf = self; 102 | self.toolbar.doneButtonTapped = ^{ [weakSelf doneButtonTapped]; }; 103 | self.toolbar.cancelButtonTapped = ^{ [weakSelf cancelButtonTapped]; }; 104 | self.toolbar.resetButtonTapped = ^{ [weakSelf resetCropViewLayout]; }; 105 | self.toolbar.clampButtonTapped = ^{ [weakSelf showAspectRatioDialog]; }; 106 | self.toolbar.rotateButtonTapped = ^{ [weakSelf rotateCropView]; }; 107 | 108 | self.transitioningDelegate = self; 109 | 110 | self.view.backgroundColor = self.cropView.backgroundColor; 111 | } 112 | 113 | - (void)viewWillAppear:(BOOL)animated 114 | { 115 | [super viewWillAppear:animated]; 116 | 117 | if ([UIApplication sharedApplication].statusBarHidden == NO) { 118 | self.inTransition = YES; 119 | [self setNeedsStatusBarAppearanceUpdate]; 120 | } 121 | } 122 | 123 | - (void)viewDidAppear:(BOOL)animated 124 | { 125 | [super viewDidAppear:animated]; 126 | self.inTransition = NO; 127 | if (animated && [UIApplication sharedApplication].statusBarHidden == NO) { 128 | [UIView animateWithDuration:0.3f animations:^{ [self setNeedsStatusBarAppearanceUpdate]; }]; 129 | 130 | if (self.cropView.gridOverlayHidden) 131 | [self.cropView setGridOverlayHidden:NO animated:YES]; 132 | } 133 | } 134 | 135 | - (void)viewWillDisappear:(BOOL)animated 136 | { 137 | [super viewWillDisappear:animated]; 138 | self.inTransition = YES; 139 | [UIView animateWithDuration:0.5f animations:^{ [self setNeedsStatusBarAppearanceUpdate]; }]; 140 | } 141 | 142 | - (void)viewDidDisappear:(BOOL)animated 143 | { 144 | [super viewDidDisappear:animated]; 145 | self.inTransition = NO; 146 | [self setNeedsStatusBarAppearanceUpdate]; 147 | } 148 | 149 | #pragma mark - Status Bar - 150 | - (UIStatusBarStyle)preferredStatusBarStyle 151 | { 152 | return UIStatusBarStyleDefault; 153 | } 154 | 155 | - (BOOL)prefersStatusBarHidden 156 | { 157 | return !self.inTransition; 158 | } 159 | 160 | - (CGRect)frameForToolBarWithVerticalLayout:(BOOL)verticalLayout 161 | { 162 | CGRect frame = self.toolbar.frame; 163 | if (verticalLayout ) { 164 | frame = self.toolbar.frame; 165 | frame.origin.x = 0.0f; 166 | frame.origin.y = 0.0f; 167 | frame.size.width = 44.0f; 168 | frame.size.height = CGRectGetHeight(self.view.frame); 169 | } 170 | else { 171 | frame.origin.x = 0.0f; 172 | frame.origin.y = CGRectGetHeight(self.view.bounds) - 44.0f; 173 | frame.size.width = CGRectGetWidth(self.view.bounds); 174 | frame.size.height = 44.0f; 175 | } 176 | 177 | return frame; 178 | } 179 | 180 | - (void)viewDidLayoutSubviews 181 | { 182 | [super viewDidLayoutSubviews]; 183 | 184 | BOOL verticalLayout = CGRectGetWidth(self.view.bounds) > CGRectGetHeight(self.view.bounds); 185 | if (verticalLayout ) { 186 | CGRect frame = self.cropView.frame; 187 | frame.origin.x = 44.0f; 188 | frame.size.width = CGRectGetWidth(self.view.bounds) - 44.0f; 189 | frame.size.height = CGRectGetHeight(self.view.bounds); 190 | self.cropView.frame = frame; 191 | } 192 | else { 193 | CGRect frame = self.cropView.frame; 194 | frame.origin.x = 0.0f; 195 | frame.size.width = CGRectGetWidth(self.view.bounds); 196 | frame.size.height = CGRectGetHeight(self.view.bounds) - 44.0f; 197 | self.cropView.frame = frame; 198 | } 199 | 200 | [UIView setAnimationsEnabled:NO]; 201 | self.toolbar.frame = [self frameForToolBarWithVerticalLayout:verticalLayout]; 202 | [self.toolbar setNeedsLayout]; 203 | [UIView setAnimationsEnabled:YES]; 204 | } 205 | 206 | #pragma mark - Rotation Handling - 207 | - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 208 | { 209 | self.snapshotView = [self.toolbar snapshotViewAfterScreenUpdates:NO]; 210 | self.snapshotView.frame = self.toolbar.frame; 211 | 212 | if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) 213 | self.snapshotView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin; 214 | else 215 | self.snapshotView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleRightMargin; 216 | 217 | [self.view addSubview:self.snapshotView]; 218 | 219 | self.toolbar.frame = [self frameForToolBarWithVerticalLayout:UIInterfaceOrientationIsLandscape(toInterfaceOrientation)]; 220 | [self.toolbar layoutIfNeeded]; 221 | 222 | self.toolbar.alpha = 0.0f; 223 | 224 | self.cropView.simpleMode = YES; 225 | [self.cropView prepareforRotation]; 226 | } 227 | 228 | - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 229 | { 230 | self.toolbar.frame = [self frameForToolBarWithVerticalLayout:UIInterfaceOrientationIsLandscape(toInterfaceOrientation)]; 231 | 232 | [UIView animateWithDuration:duration animations:^{ 233 | self.snapshotView.alpha = 0.0f; 234 | self.toolbar.alpha = 1.0f; 235 | }]; 236 | [self.cropView performRelayoutForRotation]; 237 | } 238 | 239 | - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation 240 | { 241 | [self.snapshotView removeFromSuperview]; 242 | self.snapshotView = nil; 243 | 244 | [self.cropView setSimpleMode:NO animated:YES]; 245 | } 246 | 247 | #pragma mark - Reset - 248 | - (void)resetCropViewLayout 249 | { 250 | [self.cropView resetLayoutToDefaultAnimated:YES]; 251 | self.cropView.aspectLockEnabled = NO; 252 | self.toolbar.clampButtonGlowing = NO; 253 | } 254 | 255 | #pragma mark - Aspect Ratio Handling - 256 | - (void)showAspectRatioDialog 257 | { 258 | // if (self.cropView.aspectLockEnabled) { 259 | // self.cropView.aspectLockEnabled = NO; 260 | // self.toolbar.clampButtonGlowing = NO; 261 | // return; 262 | // } 263 | // 264 | //TODO: Completely overhaul this once iOS 7 support is dropped 265 | #pragma clang diagnostic push 266 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 267 | BOOL verticalCropBox = NO; 268 | UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil 269 | delegate:self 270 | cancelButtonTitle:NSLocalizedStringFromTableInBundle(@"取消", 271 | @"TOCropViewControllerLocalizable", 272 | [NSBundle bundleForClass:[self class]], 273 | nil) 274 | destructiveButtonTitle:nil 275 | otherButtonTitles:NSLocalizedStringFromTableInBundle(@"原始", 276 | @"TOCropViewControllerLocalizable", 277 | [NSBundle bundleForClass:[self class]], 278 | nil), 279 | NSLocalizedStringFromTableInBundle(@"正方形", 280 | @"TOCropViewControllerLocalizable", 281 | [NSBundle bundleForClass:[self class]], 282 | nil), 283 | verticalCropBox ? @"2:1" : @"1:2", 284 | verticalCropBox ? @"2:3" : @"3:2", 285 | verticalCropBox ? @"3:4" : @"4:3", 286 | verticalCropBox ? @"9:16" : @"16:9",nil]; 287 | 288 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) 289 | [actionSheet showFromRect:self.toolbar.clampButtonFrame inView:self.toolbar animated:YES]; 290 | else 291 | [actionSheet showInView:self.view]; 292 | #pragma clang diagnostic pop 293 | } 294 | 295 | 296 | 297 | -(CGSize)convertAspectRatioStyleToRatio:(TOCropViewControllerAspectRatio)aspectRatioStle { 298 | CGSize aspectRatio = CGSizeZero; 299 | 300 | switch (aspectRatioStle) { 301 | case TOCropViewControllerAspectRatioOriginal: 302 | aspectRatio = CGSizeZero; 303 | break; 304 | case TOCropViewControllerAspectRatioSquare: 305 | aspectRatio = CGSizeMake(1.0f, 1.0f); 306 | break; 307 | case TOCropViewControllerAspectRatio1x2: 308 | aspectRatio = CGSizeMake(1.0f, 2.0f); 309 | break; 310 | case TOCropViewControllerAspectRatio3x2: 311 | aspectRatio = CGSizeMake(3.0f, 2.0f); 312 | break; 313 | case TOCropViewControllerAspectRatio5x3: 314 | aspectRatio = CGSizeMake(5.0f, 3.0f); 315 | break; 316 | case TOCropViewControllerAspectRatio4x3: 317 | aspectRatio = CGSizeMake(4.0f, 3.0f); 318 | break; 319 | case TOCropViewControllerAspectRatio5x4: 320 | aspectRatio = CGSizeMake(5.0f, 4.0f); 321 | break; 322 | case TOCropViewControllerAspectRatio7x5: 323 | aspectRatio = CGSizeMake(7.0f, 5.0f); 324 | break; 325 | case TOCropViewControllerAspectRatio16x9: 326 | aspectRatio = CGSizeMake(16.0f, 9.0f); 327 | break; 328 | default: 329 | break; 330 | } 331 | return aspectRatio; 332 | } 333 | - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex 334 | { 335 | CGSize aspectRatio = CGSizeZero; 336 | 337 | switch (buttonIndex) { 338 | case TOCropViewControllerAspectRatioOriginal: 339 | aspectRatio = CGSizeZero; 340 | break; 341 | case TOCropViewControllerAspectRatioSquare: 342 | aspectRatio = CGSizeMake(1.0f, 1.0f); 343 | break; 344 | case TOCropViewControllerAspectRatio1x2: 345 | aspectRatio = CGSizeMake(1.0f, 2.0f); 346 | break; 347 | case TOCropViewControllerAspectRatio3x2: 348 | aspectRatio = CGSizeMake(3.0f, 2.0f); 349 | break; 350 | case TOCropViewControllerAspectRatio5x3: 351 | aspectRatio = CGSizeMake(5.0f, 3.0f); 352 | break; 353 | case TOCropViewControllerAspectRatio4x3: 354 | aspectRatio = CGSizeMake(4.0f, 3.0f); 355 | break; 356 | case TOCropViewControllerAspectRatio5x4: 357 | aspectRatio = CGSizeMake(5.0f, 4.0f); 358 | break; 359 | case TOCropViewControllerAspectRatio7x5: 360 | aspectRatio = CGSizeMake(7.0f, 5.0f); 361 | break; 362 | case TOCropViewControllerAspectRatio16x9: 363 | aspectRatio = CGSizeMake(16.0f, 9.0f); 364 | break; 365 | default: 366 | return; 367 | } 368 | 369 | // if (self.cropView.cropBoxAspectRatioIsPortrait) { 370 | // CGFloat width = aspectRatio.width; 371 | // aspectRatio.width = aspectRatio.height; 372 | // aspectRatio.height = width; 373 | // } 374 | 375 | [self.cropView setAspectLockEnabledWithAspectRatio:aspectRatio animated:YES]; 376 | self.toolbar.clampButtonGlowing = YES; 377 | } 378 | 379 | - (void)rotateCropView 380 | { 381 | [self.cropView rotateImageNinetyDegreesAnimated:YES]; 382 | } 383 | 384 | #pragma mark - Crop View Delegates - 385 | - (void)cropViewDidBecomeResettable:(TOCropView *)cropView 386 | { 387 | self.toolbar.resetButtonEnabled = YES; 388 | } 389 | 390 | - (void)cropViewDidBecomeNonResettable:(TOCropView *)cropView 391 | { 392 | self.toolbar.resetButtonEnabled = NO; 393 | } 394 | 395 | #pragma mark - Presentation Handling - 396 | - (void)presentAnimatedFromParentViewController:(UIViewController *)viewController fromFrame:(CGRect)frame completion:(void (^)(void))completion 397 | { 398 | self.transitionController.image = self.image; 399 | self.transitionController.fromFrame = frame; 400 | 401 | __weak typeof (self) weakSelf = self; 402 | [viewController presentViewController:self animated:YES completion:^ { 403 | typeof (self) strongSelf = weakSelf; 404 | if (completion) { 405 | completion(); 406 | } 407 | 408 | [strongSelf.cropView setCroppingViewsHidden:NO animated:YES]; 409 | if (!CGRectIsEmpty(frame)) { 410 | [strongSelf.cropView setGridOverlayHidden:NO animated:YES]; 411 | } 412 | }]; 413 | } 414 | 415 | - (void)dismissAnimatedFromParentViewController:(UIViewController *)viewController withCroppedImage:(UIImage *)image toFrame:(CGRect)frame completion:(void (^)(void))completion 416 | { 417 | self.transitionController.image = image; 418 | self.transitionController.fromFrame = [self.cropView convertRect:self.cropView.cropBoxFrame toView:self.view]; 419 | self.transitionController.toFrame = frame; 420 | 421 | [viewController dismissViewControllerAnimated:YES completion:^ { 422 | if (completion) { 423 | completion(); 424 | } 425 | }]; 426 | } 427 | 428 | - (void)dismissAnimatedFromParentViewController:(UIViewController *)viewController toFrame:(CGRect)frame completion:(void (^)(void))completion 429 | { 430 | self.transitionController.image = self.image; 431 | self.transitionController.fromFrame = [self.cropView convertRect:self.cropView.imageViewFrame toView:self.view]; 432 | self.transitionController.toFrame = frame; 433 | 434 | [viewController dismissViewControllerAnimated:YES completion:^ { 435 | if (completion) { 436 | completion(); 437 | } 438 | }]; 439 | } 440 | 441 | - (id )animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source 442 | { 443 | __weak typeof (self) weakSelf = self; 444 | self.transitionController.prepareForTransitionHandler = ^{ 445 | typeof (self) strongSelf = weakSelf; 446 | strongSelf.transitionController.toFrame = [strongSelf.cropView convertRect:strongSelf.cropView.cropBoxFrame toView:strongSelf.view]; 447 | if (!CGRectIsEmpty(strongSelf.transitionController.fromFrame)) 448 | strongSelf.cropView.croppingViewsHidden = YES; 449 | 450 | if (strongSelf.prepareForTransitionHandler) 451 | strongSelf.prepareForTransitionHandler(); 452 | 453 | strongSelf.prepareForTransitionHandler = nil; 454 | }; 455 | 456 | self.transitionController.isDismissing = NO; 457 | return self.transitionController; 458 | } 459 | 460 | - (id )animationControllerForDismissedController:(UIViewController *)dismissed 461 | { 462 | __weak typeof (self) weakSelf = self; 463 | self.transitionController.prepareForTransitionHandler = ^{ 464 | typeof (self) strongSelf = weakSelf; 465 | if (!CGRectIsEmpty(strongSelf.transitionController.toFrame)) 466 | strongSelf.cropView.croppingViewsHidden = YES; 467 | else 468 | strongSelf.cropView.simpleMode = YES; 469 | 470 | if (strongSelf.prepareForTransitionHandler) 471 | strongSelf.prepareForTransitionHandler(); 472 | }; 473 | 474 | self.transitionController.isDismissing = YES; 475 | return self.transitionController; 476 | } 477 | 478 | #pragma mark - Button Feedback - 479 | - (void)cancelButtonTapped 480 | { 481 | if ([self.delegate respondsToSelector:@selector(cropViewController:didFinishCancelled:)]) { 482 | [self.delegate cropViewController:self didFinishCancelled:YES]; 483 | return; 484 | } 485 | 486 | self.modalTransitionStyle = UIModalTransitionStyleCoverVertical; 487 | [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; 488 | } 489 | 490 | - (void)doneButtonTapped 491 | { 492 | CGRect cropFrame = self.cropView.croppedImageFrame; 493 | NSInteger angle = self.cropView.angle; 494 | 495 | //If desired, when the user taps done, show an activity sheet 496 | if (self.showActivitySheetOnDone) { 497 | TOActivityCroppedImageProvider *imageItem = [[TOActivityCroppedImageProvider alloc] initWithImage:self.image cropFrame:cropFrame angle:angle]; 498 | TOCroppedImageAttributes *attributes = [[TOCroppedImageAttributes alloc] initWithCroppedFrame:cropFrame angle:angle originalImageSize:self.image.size]; 499 | 500 | NSMutableArray *activityItems = [@[imageItem, attributes] mutableCopy]; 501 | if (self.activityItems) 502 | [activityItems addObjectsFromArray:self.activityItems]; 503 | 504 | UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:self.applicationActivities]; 505 | activityController.excludedActivityTypes = self.excludedActivityTypes; 506 | 507 | if (NSClassFromString(@"UIPopoverPresentationController")) { 508 | activityController.modalPresentationStyle = UIModalPresentationPopover; 509 | activityController.popoverPresentationController.sourceView = self.toolbar; 510 | activityController.popoverPresentationController.sourceRect = self.toolbar.doneButtonFrame; 511 | [self presentViewController:activityController animated:YES completion:nil]; 512 | } 513 | else { 514 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { 515 | [self presentViewController:activityController animated:YES completion:nil]; 516 | } 517 | else { 518 | #pragma clang diagnostic push 519 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 520 | [self.activityPopoverController dismissPopoverAnimated:NO]; 521 | self.activityPopoverController = [[UIPopoverController alloc] initWithContentViewController:activityController]; 522 | [self.activityPopoverController presentPopoverFromRect:self.toolbar.doneButtonFrame inView:self.toolbar permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; 523 | #pragma clang diagnostic pop 524 | } 525 | } 526 | __weak typeof(activityController) blockController = activityController; 527 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0 528 | activityController.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) { 529 | if (!completed) 530 | return; 531 | 532 | if ([self.delegate respondsToSelector:@selector(cropViewController:didFinishCancelled:)]) { 533 | [self.delegate cropViewController:self didFinishCancelled:NO]; 534 | } 535 | else { 536 | [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; 537 | blockController.completionWithItemsHandler = nil; 538 | } 539 | }; 540 | #else 541 | activityController.completionHandler = ^(NSString *activityType, BOOL completed) { 542 | if (!completed) 543 | return; 544 | 545 | if ([self.delegate respondsToSelector:@selector(cropViewController:didFinishCancelled:)]) { 546 | [self.delegate cropViewController:self didFinishCancelled:NO]; 547 | } 548 | else { 549 | [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; 550 | blockController.completionHandler = nil; 551 | } 552 | }; 553 | #endif 554 | 555 | return; 556 | } 557 | 558 | //If the delegate that only supplies crop data is provided, call it 559 | if ([self.delegate respondsToSelector:@selector(cropViewController:didCropImageToRect:angle:)]) { 560 | [self.delegate cropViewController:self didCropImageToRect:cropFrame angle:angle]; 561 | } 562 | //If the delegate that requires the specific cropped image is provided, call it 563 | else if ([self.delegate respondsToSelector:@selector(cropViewController:didCropToImage:withRect:angle:)]) { 564 | UIImage *image = nil; 565 | if (angle == 0 && CGRectEqualToRect(cropFrame, (CGRect){CGPointZero, self.image.size})) { 566 | image = self.image; 567 | } 568 | else { 569 | image = [self.image croppedImageWithFrame:cropFrame angle:angle]; 570 | } 571 | 572 | //dispatch on the next run-loop so the animation isn't interuppted by the crop operation 573 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.03f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 574 | [self.delegate cropViewController:self didCropToImage:image withRect:cropFrame angle:angle]; 575 | }); 576 | } 577 | else { 578 | [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; 579 | } 580 | } 581 | 582 | @end 583 | -------------------------------------------------------------------------------- /PureCamera/TOCropViewControllerLocalizable.strings: -------------------------------------------------------------------------------- 1 | "Done" = "Done"; 2 | "Cancel" = "Cancel"; 3 | "Reset" = "Reset"; 4 | "Original" = "Original"; 5 | "Square" = "Square"; -------------------------------------------------------------------------------- /PureCamera/TOCropViewControllerTransitioning.h: -------------------------------------------------------------------------------- 1 | // 2 | // TOCropViewControllerTransitioning.h 3 | // 4 | // Copyright 2015 Timothy Oliver. All rights reserved. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | #import 24 | #import 25 | 26 | @interface TOCropViewControllerTransitioning : NSObject 27 | 28 | @property (nonatomic, assign) BOOL isDismissing; 29 | 30 | @property (nonatomic, strong) UIImage *image; 31 | @property (nonatomic, assign) CGRect fromFrame; 32 | @property (nonatomic, assign) CGRect toFrame; 33 | 34 | @property (nonatomic, copy) void (^prepareForTransitionHandler)(void); 35 | 36 | - (void)reset; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /PureCamera/TOCropViewControllerTransitioning.m: -------------------------------------------------------------------------------- 1 | // 2 | // TOCropViewControllerTransitioning.m 3 | // 4 | // Copyright 2015 Timothy Oliver. All rights reserved. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | #import "TOCropViewControllerTransitioning.h" 24 | #import 25 | 26 | @implementation TOCropViewControllerTransitioning 27 | 28 | - (NSTimeInterval)transitionDuration:(id )transitionContext 29 | { 30 | return 0.45f; 31 | } 32 | 33 | - (void)animateTransition:(id )transitionContext 34 | { 35 | UIView *containerView = [transitionContext containerView]; 36 | 37 | UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 38 | UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 39 | 40 | UIViewController *cropViewController = (self.isDismissing == NO) ? toViewController : fromViewController; 41 | UIViewController *previousController = (self.isDismissing == NO) ? fromViewController : toViewController; 42 | 43 | cropViewController.view.frame = containerView.bounds; 44 | previousController.view.frame = containerView.bounds; 45 | 46 | UIImageView *imageView = nil; 47 | if ((self.isDismissing && !CGRectIsEmpty(self.toFrame)) || (!self.isDismissing && !CGRectIsEmpty(self.fromFrame))) { 48 | imageView = [[UIImageView alloc] initWithImage:self.image]; 49 | imageView.frame = self.fromFrame; 50 | [containerView addSubview:imageView]; 51 | } 52 | 53 | if (self.isDismissing == NO) { 54 | [containerView addSubview:cropViewController.view]; 55 | [containerView bringSubviewToFront:imageView]; 56 | } 57 | else { 58 | [containerView insertSubview:previousController.view belowSubview:cropViewController.view]; 59 | } 60 | 61 | if (self.prepareForTransitionHandler) 62 | self.prepareForTransitionHandler(); 63 | 64 | cropViewController.view.alpha = (self.isDismissing ? 1.0f : 0.0f); 65 | if (imageView) { 66 | [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0f usingSpringWithDamping:1.0f initialSpringVelocity:0.7f options:0 animations:^{ 67 | imageView.frame = self.toFrame; 68 | } completion:^(BOOL complete) { 69 | [imageView removeFromSuperview]; 70 | }]; 71 | } 72 | 73 | [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{ 74 | cropViewController.view.alpha = (self.isDismissing ? 0.0f : 1.0f); 75 | } completion:^(BOOL complete) { 76 | [self reset]; 77 | [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; 78 | }]; 79 | } 80 | 81 | - (void)reset 82 | { 83 | self.image = nil; 84 | self.fromFrame = CGRectZero; 85 | self.toFrame = CGRectZero; 86 | self.prepareForTransitionHandler = nil; 87 | } 88 | 89 | @end 90 | -------------------------------------------------------------------------------- /PureCamera/TOCroppedImageAttributes.h: -------------------------------------------------------------------------------- 1 | // 2 | // TOCroppedImageAttributes.h 3 | // 4 | // Copyright 2015 Timothy Oliver. All rights reserved. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | #import 24 | #import 25 | 26 | @interface TOCroppedImageAttributes : NSObject 27 | 28 | @property (nonatomic, readonly) NSInteger angle; 29 | @property (nonatomic, readonly) CGRect croppedFrame; 30 | @property (nonatomic, readonly) CGSize originalImageSize; 31 | 32 | - (instancetype)initWithCroppedFrame:(CGRect)croppedFrame angle:(NSInteger)angle originalImageSize:(CGSize)originalSize; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /PureCamera/TOCroppedImageAttributes.m: -------------------------------------------------------------------------------- 1 | // 2 | // TOCroppedImageAttributes.m 3 | // 4 | // Copyright 2015 Timothy Oliver. All rights reserved. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | #import "TOCroppedImageAttributes.h" 24 | 25 | @interface TOCroppedImageAttributes () 26 | 27 | @property (nonatomic, assign, readwrite) NSInteger angle; 28 | @property (nonatomic, assign, readwrite) CGRect croppedFrame; 29 | @property (nonatomic, assign, readwrite) CGSize originalImageSize; 30 | 31 | @end 32 | 33 | @implementation TOCroppedImageAttributes 34 | 35 | - (instancetype)initWithCroppedFrame:(CGRect)croppedFrame angle:(NSInteger)angle originalImageSize:(CGSize)originalSize 36 | { 37 | if (self = [super init]) { 38 | _angle = angle; 39 | _croppedFrame = croppedFrame; 40 | _originalImageSize = originalSize; 41 | } 42 | 43 | return self; 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /PureCamera/UIImage+CropRotate.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+CropRotate.h 3 | // 4 | // Copyright 2015 Timothy Oliver. All rights reserved. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | #import 24 | 25 | @interface UIImage (CropRotate) 26 | 27 | - (UIImage *)croppedImageWithFrame:(CGRect)frame angle:(NSInteger)angle; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /PureCamera/UIImage+CropRotate.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+CropRotate.m 3 | // 4 | // Copyright 2015 Timothy Oliver. All rights reserved. 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 21 | // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | #import "UIImage+CropRotate.h" 24 | 25 | @implementation UIImage (CropRotate) 26 | 27 | - (UIImage *)croppedImageWithFrame:(CGRect)frame angle:(NSInteger)angle 28 | { 29 | UIImage *croppedImage = nil; 30 | CGPoint drawPoint = CGPointZero; 31 | 32 | UIGraphicsBeginImageContextWithOptions(frame.size, YES, self.scale); 33 | { 34 | CGContextRef context = UIGraphicsGetCurrentContext(); 35 | 36 | //To conserve memory in not needing to completely re-render the image re-rotated, 37 | //map the image to a view and then use Core Animation to manipulate its rotation 38 | if (angle != 0) { 39 | UIImageView *imageView = [[UIImageView alloc] initWithImage:self]; 40 | imageView.layer.minificationFilter = @"nearest"; 41 | imageView.layer.magnificationFilter = @"neareset"; 42 | imageView.transform = CGAffineTransformRotate(CGAffineTransformIdentity, angle * (M_PI/180.0f)); 43 | CGRect rotatedRect = CGRectApplyAffineTransform(imageView.bounds, imageView.transform); 44 | UIView *containerView = [[UIView alloc] initWithFrame:(CGRect){CGPointZero, rotatedRect.size}]; 45 | [containerView addSubview:imageView]; 46 | imageView.center = containerView.center; 47 | CGContextTranslateCTM(context, -frame.origin.x, -frame.origin.y); 48 | [containerView.layer renderInContext:context]; 49 | } 50 | else { 51 | CGContextTranslateCTM(context, -frame.origin.x, -frame.origin.y); 52 | [self drawAtPoint:drawPoint]; 53 | } 54 | 55 | croppedImage = UIGraphicsGetImageFromCurrentImageContext(); 56 | } 57 | UIGraphicsEndImageContext(); 58 | 59 | return croppedImage; 60 | } 61 | 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /PureCamera/UIImage+FixOrientation.h: -------------------------------------------------------------------------------- 1 | // http://stackoverflow.com/questions/5427656/ios-uiimagepickercontroller-result-image-orientation-after-upload 2 | 3 | 4 | 5 | #import 6 | 7 | @interface UIImage(fixOrientation) 8 | - (UIImage *)fixOrientation; 9 | @end 10 | -------------------------------------------------------------------------------- /PureCamera/UIImage+FixOrientation.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | #import "UIImage+FixOrientation.h" 4 | 5 | @implementation UIImage (fixOrientation) 6 | 7 | - (UIImage *)fixOrientation { 8 | 9 | // No-op if the orientation is already correct 10 | if (self.imageOrientation == UIImageOrientationUp) return self; 11 | 12 | // We need to calculate the proper transformation to make the image upright. 13 | // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored. 14 | CGAffineTransform transform = CGAffineTransformIdentity; 15 | 16 | switch (self.imageOrientation) { 17 | case UIImageOrientationDown: 18 | case UIImageOrientationDownMirrored: 19 | transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height); 20 | transform = CGAffineTransformRotate(transform, M_PI); 21 | break; 22 | 23 | case UIImageOrientationLeft: 24 | case UIImageOrientationLeftMirrored: 25 | transform = CGAffineTransformTranslate(transform, self.size.width, 0); 26 | transform = CGAffineTransformRotate(transform, M_PI_2); 27 | break; 28 | 29 | case UIImageOrientationRight: 30 | case UIImageOrientationRightMirrored: 31 | transform = CGAffineTransformTranslate(transform, 0, self.size.height); 32 | transform = CGAffineTransformRotate(transform, -M_PI_2); 33 | break; 34 | case UIImageOrientationUp: 35 | case UIImageOrientationUpMirrored: 36 | break; 37 | } 38 | 39 | switch (self.imageOrientation) { 40 | case UIImageOrientationUpMirrored: 41 | case UIImageOrientationDownMirrored: 42 | transform = CGAffineTransformTranslate(transform, self.size.width, 0); 43 | transform = CGAffineTransformScale(transform, -1, 1); 44 | break; 45 | 46 | case UIImageOrientationLeftMirrored: 47 | case UIImageOrientationRightMirrored: 48 | transform = CGAffineTransformTranslate(transform, self.size.height, 0); 49 | transform = CGAffineTransformScale(transform, -1, 1); 50 | break; 51 | case UIImageOrientationUp: 52 | case UIImageOrientationDown: 53 | case UIImageOrientationLeft: 54 | case UIImageOrientationRight: 55 | break; 56 | } 57 | 58 | // Now we draw the underlying CGImage into a new context, applying the transform 59 | // calculated above. 60 | CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height, 61 | CGImageGetBitsPerComponent(self.CGImage), 0, 62 | CGImageGetColorSpace(self.CGImage), 63 | CGImageGetBitmapInfo(self.CGImage)); 64 | CGContextConcatCTM(ctx, transform); 65 | switch (self.imageOrientation) { 66 | case UIImageOrientationLeft: 67 | case UIImageOrientationLeftMirrored: 68 | case UIImageOrientationRight: 69 | case UIImageOrientationRightMirrored: 70 | // Grr... 71 | CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage); 72 | break; 73 | 74 | default: 75 | CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage); 76 | break; 77 | } 78 | 79 | // And now we just create a new UIImage from the drawing context 80 | CGImageRef cgimg = CGBitmapContextCreateImage(ctx); 81 | UIImage *img = [UIImage imageWithCGImage:cgimg]; 82 | CGContextRelease(ctx); 83 | CGImageRelease(cgimg); 84 | return img; 85 | } 86 | 87 | @end 88 | -------------------------------------------------------------------------------- /PureCamerademo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1D53DF0E1F48343000534C17 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D53DF051F48343000534C17 /* AppDelegate.m */; }; 11 | 1D53DF0F1F48343000534C17 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1D53DF061F48343000534C17 /* Assets.xcassets */; }; 12 | 1D53DF101F48343000534C17 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1D53DF071F48343000534C17 /* LaunchScreen.storyboard */; }; 13 | 1D53DF111F48343000534C17 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1D53DF091F48343000534C17 /* Main.storyboard */; }; 14 | 1D53DF121F48343000534C17 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D53DF0B1F48343000534C17 /* main.m */; }; 15 | 1D53DF131F48343000534C17 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D53DF0D1F48343000534C17 /* ViewController.m */; }; 16 | 6C163CC520AF159700CB5DB0 /* TOActivityCroppedImageProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C163CA920AF159700CB5DB0 /* TOActivityCroppedImageProvider.m */; }; 17 | 6C163CC620AF159700CB5DB0 /* UIImage+CropRotate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C163CAB20AF159700CB5DB0 /* UIImage+CropRotate.m */; }; 18 | 6C163CC720AF159700CB5DB0 /* TOCropViewControllerTransitioning.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C163CAD20AF159700CB5DB0 /* TOCropViewControllerTransitioning.m */; }; 19 | 6C163CC820AF159700CB5DB0 /* LLSimpleCamera+Helper.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C163CAE20AF159700CB5DB0 /* LLSimpleCamera+Helper.m */; }; 20 | 6C163CC920AF159700CB5DB0 /* TOCroppedImageAttributes.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C163CB120AF159700CB5DB0 /* TOCroppedImageAttributes.m */; }; 21 | 6C163CCA20AF159700CB5DB0 /* PureCamera.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 6C163CB220AF159700CB5DB0 /* PureCamera.bundle */; }; 22 | 6C163CCB20AF159700CB5DB0 /* TOCropScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C163CB520AF159700CB5DB0 /* TOCropScrollView.m */; }; 23 | 6C163CCC20AF159700CB5DB0 /* TOCropViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C163CB620AF159700CB5DB0 /* TOCropViewController.m */; }; 24 | 6C163CCD20AF159700CB5DB0 /* TOCropViewControllerLocalizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6C163CB720AF159700CB5DB0 /* TOCropViewControllerLocalizable.strings */; }; 25 | 6C163CCE20AF159700CB5DB0 /* TOCropView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C163CB820AF159700CB5DB0 /* TOCropView.m */; }; 26 | 6C163CCF20AF159700CB5DB0 /* TOCropOverlayView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C163CBA20AF159700CB5DB0 /* TOCropOverlayView.m */; }; 27 | 6C163CD020AF159700CB5DB0 /* PureCamera.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C163CBD20AF159700CB5DB0 /* PureCamera.m */; }; 28 | 6C163CD120AF159700CB5DB0 /* TOCropToolbar.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C163CBF20AF159700CB5DB0 /* TOCropToolbar.m */; }; 29 | 6C163CD220AF159700CB5DB0 /* LLSimpleCamera.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C163CC120AF159700CB5DB0 /* LLSimpleCamera.m */; }; 30 | 6C163CD320AF159700CB5DB0 /* UIImage+FixOrientation.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C163CC420AF159700CB5DB0 /* UIImage+FixOrientation.m */; }; 31 | 6C163CD620AF165B00CB5DB0 /* PureCropVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C163CD520AF165B00CB5DB0 /* PureCropVC.m */; }; 32 | 6C397B262065003600B3B864 /* KModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C397B252065003500B3B864 /* KModel.m */; }; 33 | /* End PBXBuildFile section */ 34 | 35 | /* Begin PBXFileReference section */ 36 | 1D53DF041F48343000534C17 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 37 | 1D53DF051F48343000534C17 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 38 | 1D53DF061F48343000534C17 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 39 | 1D53DF081F48343000534C17 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 40 | 1D53DF0A1F48343000534C17 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 41 | 1D53DF0B1F48343000534C17 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 42 | 1D53DF0C1F48343000534C17 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 43 | 1D53DF0D1F48343000534C17 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 44 | 1DD4F5021DDC676600F0D6B0 /* PureCamerademo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PureCamerademo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | 6C163CA920AF159700CB5DB0 /* TOActivityCroppedImageProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TOActivityCroppedImageProvider.m; sourceTree = ""; }; 46 | 6C163CAA20AF159700CB5DB0 /* TOCropView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TOCropView.h; sourceTree = ""; }; 47 | 6C163CAB20AF159700CB5DB0 /* UIImage+CropRotate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+CropRotate.m"; sourceTree = ""; }; 48 | 6C163CAC20AF159700CB5DB0 /* PureCamera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PureCamera.h; sourceTree = ""; }; 49 | 6C163CAD20AF159700CB5DB0 /* TOCropViewControllerTransitioning.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TOCropViewControllerTransitioning.m; sourceTree = ""; }; 50 | 6C163CAE20AF159700CB5DB0 /* LLSimpleCamera+Helper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "LLSimpleCamera+Helper.m"; sourceTree = ""; }; 51 | 6C163CAF20AF159700CB5DB0 /* TOCropOverlayView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TOCropOverlayView.h; sourceTree = ""; }; 52 | 6C163CB020AF159700CB5DB0 /* LLSimpleCamera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLSimpleCamera.h; sourceTree = ""; }; 53 | 6C163CB120AF159700CB5DB0 /* TOCroppedImageAttributes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TOCroppedImageAttributes.m; sourceTree = ""; }; 54 | 6C163CB220AF159700CB5DB0 /* PureCamera.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = PureCamera.bundle; sourceTree = ""; }; 55 | 6C163CB320AF159700CB5DB0 /* TOCropToolbar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TOCropToolbar.h; sourceTree = ""; }; 56 | 6C163CB420AF159700CB5DB0 /* UIImage+FixOrientation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+FixOrientation.h"; sourceTree = ""; }; 57 | 6C163CB520AF159700CB5DB0 /* TOCropScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TOCropScrollView.m; sourceTree = ""; }; 58 | 6C163CB620AF159700CB5DB0 /* TOCropViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TOCropViewController.m; sourceTree = ""; }; 59 | 6C163CB720AF159700CB5DB0 /* TOCropViewControllerLocalizable.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = TOCropViewControllerLocalizable.strings; sourceTree = ""; }; 60 | 6C163CB820AF159700CB5DB0 /* TOCropView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TOCropView.m; sourceTree = ""; }; 61 | 6C163CB920AF159700CB5DB0 /* TOActivityCroppedImageProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TOActivityCroppedImageProvider.h; sourceTree = ""; }; 62 | 6C163CBA20AF159700CB5DB0 /* TOCropOverlayView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TOCropOverlayView.m; sourceTree = ""; }; 63 | 6C163CBB20AF159700CB5DB0 /* LLSimpleCamera+Helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "LLSimpleCamera+Helper.h"; sourceTree = ""; }; 64 | 6C163CBC20AF159700CB5DB0 /* TOCropViewControllerTransitioning.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TOCropViewControllerTransitioning.h; sourceTree = ""; }; 65 | 6C163CBD20AF159700CB5DB0 /* PureCamera.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PureCamera.m; sourceTree = ""; }; 66 | 6C163CBE20AF159700CB5DB0 /* UIImage+CropRotate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+CropRotate.h"; sourceTree = ""; }; 67 | 6C163CBF20AF159700CB5DB0 /* TOCropToolbar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TOCropToolbar.m; sourceTree = ""; }; 68 | 6C163CC020AF159700CB5DB0 /* TOCroppedImageAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TOCroppedImageAttributes.h; sourceTree = ""; }; 69 | 6C163CC120AF159700CB5DB0 /* LLSimpleCamera.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LLSimpleCamera.m; sourceTree = ""; }; 70 | 6C163CC220AF159700CB5DB0 /* TOCropViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TOCropViewController.h; sourceTree = ""; }; 71 | 6C163CC320AF159700CB5DB0 /* TOCropScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TOCropScrollView.h; sourceTree = ""; }; 72 | 6C163CC420AF159700CB5DB0 /* UIImage+FixOrientation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+FixOrientation.m"; sourceTree = ""; }; 73 | 6C163CD420AF165B00CB5DB0 /* PureCropVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PureCropVC.h; sourceTree = ""; }; 74 | 6C163CD520AF165B00CB5DB0 /* PureCropVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PureCropVC.m; sourceTree = ""; }; 75 | 6C1D93111F48591100AE1102 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ../../Info.plist; sourceTree = ""; }; 76 | 6C397B242065003500B3B864 /* KModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KModel.h; sourceTree = ""; }; 77 | 6C397B252065003500B3B864 /* KModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KModel.m; sourceTree = ""; }; 78 | /* End PBXFileReference section */ 79 | 80 | /* Begin PBXFrameworksBuildPhase section */ 81 | 1DD4F4FF1DDC676600F0D6B0 /* Frameworks */ = { 82 | isa = PBXFrameworksBuildPhase; 83 | buildActionMask = 2147483647; 84 | files = ( 85 | ); 86 | runOnlyForDeploymentPostprocessing = 0; 87 | }; 88 | /* End PBXFrameworksBuildPhase section */ 89 | 90 | /* Begin PBXGroup section */ 91 | 1D53DF021F48343000534C17 /* PureCamerademo */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 1D53DF031F48343000534C17 /* PureCamerademo */, 95 | ); 96 | path = PureCamerademo; 97 | sourceTree = ""; 98 | }; 99 | 1D53DF031F48343000534C17 /* PureCamerademo */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 6C1D93111F48591100AE1102 /* Info.plist */, 103 | 1D53DF041F48343000534C17 /* AppDelegate.h */, 104 | 1D53DF051F48343000534C17 /* AppDelegate.m */, 105 | 1D53DF061F48343000534C17 /* Assets.xcassets */, 106 | 1D53DF071F48343000534C17 /* LaunchScreen.storyboard */, 107 | 1D53DF091F48343000534C17 /* Main.storyboard */, 108 | 1D53DF0B1F48343000534C17 /* main.m */, 109 | 1D53DF0C1F48343000534C17 /* ViewController.h */, 110 | 1D53DF0D1F48343000534C17 /* ViewController.m */, 111 | 6C397B242065003500B3B864 /* KModel.h */, 112 | 6C397B252065003500B3B864 /* KModel.m */, 113 | ); 114 | path = PureCamerademo; 115 | sourceTree = ""; 116 | }; 117 | 1DD4F4F91DDC676600F0D6B0 = { 118 | isa = PBXGroup; 119 | children = ( 120 | 6C163CA820AF159700CB5DB0 /* PureCamera */, 121 | 1D53DF021F48343000534C17 /* PureCamerademo */, 122 | 1DD4F5031DDC676600F0D6B0 /* Products */, 123 | ); 124 | sourceTree = ""; 125 | }; 126 | 1DD4F5031DDC676600F0D6B0 /* Products */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 1DD4F5021DDC676600F0D6B0 /* PureCamerademo.app */, 130 | ); 131 | name = Products; 132 | sourceTree = ""; 133 | }; 134 | 6C163CA820AF159700CB5DB0 /* PureCamera */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | 6C163CD420AF165B00CB5DB0 /* PureCropVC.h */, 138 | 6C163CD520AF165B00CB5DB0 /* PureCropVC.m */, 139 | 6C163CA920AF159700CB5DB0 /* TOActivityCroppedImageProvider.m */, 140 | 6C163CAA20AF159700CB5DB0 /* TOCropView.h */, 141 | 6C163CAB20AF159700CB5DB0 /* UIImage+CropRotate.m */, 142 | 6C163CAC20AF159700CB5DB0 /* PureCamera.h */, 143 | 6C163CAD20AF159700CB5DB0 /* TOCropViewControllerTransitioning.m */, 144 | 6C163CAE20AF159700CB5DB0 /* LLSimpleCamera+Helper.m */, 145 | 6C163CAF20AF159700CB5DB0 /* TOCropOverlayView.h */, 146 | 6C163CB020AF159700CB5DB0 /* LLSimpleCamera.h */, 147 | 6C163CB120AF159700CB5DB0 /* TOCroppedImageAttributes.m */, 148 | 6C163CB220AF159700CB5DB0 /* PureCamera.bundle */, 149 | 6C163CB320AF159700CB5DB0 /* TOCropToolbar.h */, 150 | 6C163CB420AF159700CB5DB0 /* UIImage+FixOrientation.h */, 151 | 6C163CB520AF159700CB5DB0 /* TOCropScrollView.m */, 152 | 6C163CB620AF159700CB5DB0 /* TOCropViewController.m */, 153 | 6C163CB720AF159700CB5DB0 /* TOCropViewControllerLocalizable.strings */, 154 | 6C163CB820AF159700CB5DB0 /* TOCropView.m */, 155 | 6C163CB920AF159700CB5DB0 /* TOActivityCroppedImageProvider.h */, 156 | 6C163CBA20AF159700CB5DB0 /* TOCropOverlayView.m */, 157 | 6C163CBB20AF159700CB5DB0 /* LLSimpleCamera+Helper.h */, 158 | 6C163CBC20AF159700CB5DB0 /* TOCropViewControllerTransitioning.h */, 159 | 6C163CBD20AF159700CB5DB0 /* PureCamera.m */, 160 | 6C163CBE20AF159700CB5DB0 /* UIImage+CropRotate.h */, 161 | 6C163CBF20AF159700CB5DB0 /* TOCropToolbar.m */, 162 | 6C163CC020AF159700CB5DB0 /* TOCroppedImageAttributes.h */, 163 | 6C163CC120AF159700CB5DB0 /* LLSimpleCamera.m */, 164 | 6C163CC220AF159700CB5DB0 /* TOCropViewController.h */, 165 | 6C163CC320AF159700CB5DB0 /* TOCropScrollView.h */, 166 | 6C163CC420AF159700CB5DB0 /* UIImage+FixOrientation.m */, 167 | ); 168 | path = PureCamera; 169 | sourceTree = ""; 170 | }; 171 | /* End PBXGroup section */ 172 | 173 | /* Begin PBXNativeTarget section */ 174 | 1DD4F5011DDC676600F0D6B0 /* PureCamerademo */ = { 175 | isa = PBXNativeTarget; 176 | buildConfigurationList = 1DD4F52F1DDC676600F0D6B0 /* Build configuration list for PBXNativeTarget "PureCamerademo" */; 177 | buildPhases = ( 178 | 1DD4F4FE1DDC676600F0D6B0 /* Sources */, 179 | 1DD4F4FF1DDC676600F0D6B0 /* Frameworks */, 180 | 1DD4F5001DDC676600F0D6B0 /* Resources */, 181 | ); 182 | buildRules = ( 183 | ); 184 | dependencies = ( 185 | ); 186 | name = PureCamerademo; 187 | productName = SKFCamerademo; 188 | productReference = 1DD4F5021DDC676600F0D6B0 /* PureCamerademo.app */; 189 | productType = "com.apple.product-type.application"; 190 | }; 191 | /* End PBXNativeTarget section */ 192 | 193 | /* Begin PBXProject section */ 194 | 1DD4F4FA1DDC676600F0D6B0 /* Project object */ = { 195 | isa = PBXProject; 196 | attributes = { 197 | LastUpgradeCheck = 0810; 198 | ORGANIZATIONNAME = "五月"; 199 | TargetAttributes = { 200 | 1DD4F5011DDC676600F0D6B0 = { 201 | CreatedOnToolsVersion = 8.1; 202 | DevelopmentTeam = AA4YKUFB2C; 203 | ProvisioningStyle = Automatic; 204 | }; 205 | }; 206 | }; 207 | buildConfigurationList = 1DD4F4FD1DDC676600F0D6B0 /* Build configuration list for PBXProject "PureCamerademo" */; 208 | compatibilityVersion = "Xcode 3.2"; 209 | developmentRegion = English; 210 | hasScannedForEncodings = 0; 211 | knownRegions = ( 212 | English, 213 | en, 214 | Base, 215 | ); 216 | mainGroup = 1DD4F4F91DDC676600F0D6B0; 217 | productRefGroup = 1DD4F5031DDC676600F0D6B0 /* Products */; 218 | projectDirPath = ""; 219 | projectRoot = ""; 220 | targets = ( 221 | 1DD4F5011DDC676600F0D6B0 /* PureCamerademo */, 222 | ); 223 | }; 224 | /* End PBXProject section */ 225 | 226 | /* Begin PBXResourcesBuildPhase section */ 227 | 1DD4F5001DDC676600F0D6B0 /* Resources */ = { 228 | isa = PBXResourcesBuildPhase; 229 | buildActionMask = 2147483647; 230 | files = ( 231 | 6C163CCA20AF159700CB5DB0 /* PureCamera.bundle in Resources */, 232 | 1D53DF0F1F48343000534C17 /* Assets.xcassets in Resources */, 233 | 6C163CCD20AF159700CB5DB0 /* TOCropViewControllerLocalizable.strings in Resources */, 234 | 1D53DF111F48343000534C17 /* Main.storyboard in Resources */, 235 | 1D53DF101F48343000534C17 /* LaunchScreen.storyboard in Resources */, 236 | ); 237 | runOnlyForDeploymentPostprocessing = 0; 238 | }; 239 | /* End PBXResourcesBuildPhase section */ 240 | 241 | /* Begin PBXSourcesBuildPhase section */ 242 | 1DD4F4FE1DDC676600F0D6B0 /* Sources */ = { 243 | isa = PBXSourcesBuildPhase; 244 | buildActionMask = 2147483647; 245 | files = ( 246 | 6C163CC820AF159700CB5DB0 /* LLSimpleCamera+Helper.m in Sources */, 247 | 6C163CC620AF159700CB5DB0 /* UIImage+CropRotate.m in Sources */, 248 | 6C163CCF20AF159700CB5DB0 /* TOCropOverlayView.m in Sources */, 249 | 1D53DF131F48343000534C17 /* ViewController.m in Sources */, 250 | 6C163CCC20AF159700CB5DB0 /* TOCropViewController.m in Sources */, 251 | 6C163CC920AF159700CB5DB0 /* TOCroppedImageAttributes.m in Sources */, 252 | 6C163CD220AF159700CB5DB0 /* LLSimpleCamera.m in Sources */, 253 | 6C163CD020AF159700CB5DB0 /* PureCamera.m in Sources */, 254 | 6C163CC720AF159700CB5DB0 /* TOCropViewControllerTransitioning.m in Sources */, 255 | 1D53DF121F48343000534C17 /* main.m in Sources */, 256 | 6C397B262065003600B3B864 /* KModel.m in Sources */, 257 | 6C163CD320AF159700CB5DB0 /* UIImage+FixOrientation.m in Sources */, 258 | 1D53DF0E1F48343000534C17 /* AppDelegate.m in Sources */, 259 | 6C163CCE20AF159700CB5DB0 /* TOCropView.m in Sources */, 260 | 6C163CCB20AF159700CB5DB0 /* TOCropScrollView.m in Sources */, 261 | 6C163CC520AF159700CB5DB0 /* TOActivityCroppedImageProvider.m in Sources */, 262 | 6C163CD620AF165B00CB5DB0 /* PureCropVC.m in Sources */, 263 | 6C163CD120AF159700CB5DB0 /* TOCropToolbar.m in Sources */, 264 | ); 265 | runOnlyForDeploymentPostprocessing = 0; 266 | }; 267 | /* End PBXSourcesBuildPhase section */ 268 | 269 | /* Begin PBXVariantGroup section */ 270 | 1D53DF071F48343000534C17 /* LaunchScreen.storyboard */ = { 271 | isa = PBXVariantGroup; 272 | children = ( 273 | 1D53DF081F48343000534C17 /* Base */, 274 | ); 275 | name = LaunchScreen.storyboard; 276 | sourceTree = ""; 277 | }; 278 | 1D53DF091F48343000534C17 /* Main.storyboard */ = { 279 | isa = PBXVariantGroup; 280 | children = ( 281 | 1D53DF0A1F48343000534C17 /* Base */, 282 | ); 283 | name = Main.storyboard; 284 | sourceTree = ""; 285 | }; 286 | /* End PBXVariantGroup section */ 287 | 288 | /* Begin XCBuildConfiguration section */ 289 | 1DD4F52D1DDC676600F0D6B0 /* Debug */ = { 290 | isa = XCBuildConfiguration; 291 | buildSettings = { 292 | ALWAYS_SEARCH_USER_PATHS = NO; 293 | CLANG_ANALYZER_NONNULL = YES; 294 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 295 | CLANG_CXX_LIBRARY = "libc++"; 296 | CLANG_ENABLE_MODULES = YES; 297 | CLANG_ENABLE_OBJC_ARC = YES; 298 | CLANG_WARN_BOOL_CONVERSION = YES; 299 | CLANG_WARN_CONSTANT_CONVERSION = YES; 300 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 301 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 302 | CLANG_WARN_EMPTY_BODY = YES; 303 | CLANG_WARN_ENUM_CONVERSION = YES; 304 | CLANG_WARN_INFINITE_RECURSION = YES; 305 | CLANG_WARN_INT_CONVERSION = YES; 306 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 307 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 308 | CLANG_WARN_UNREACHABLE_CODE = YES; 309 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 310 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 311 | COPY_PHASE_STRIP = NO; 312 | DEBUG_INFORMATION_FORMAT = dwarf; 313 | ENABLE_STRICT_OBJC_MSGSEND = YES; 314 | ENABLE_TESTABILITY = YES; 315 | FRAMEWORK_SEARCH_PATHS = ""; 316 | GCC_C_LANGUAGE_STANDARD = gnu99; 317 | GCC_DYNAMIC_NO_PIC = NO; 318 | GCC_NO_COMMON_BLOCKS = YES; 319 | GCC_OPTIMIZATION_LEVEL = 0; 320 | GCC_PREPROCESSOR_DEFINITIONS = ( 321 | "DEBUG=1", 322 | "$(inherited)", 323 | ); 324 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 325 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 326 | GCC_WARN_UNDECLARED_SELECTOR = YES; 327 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 328 | GCC_WARN_UNUSED_FUNCTION = YES; 329 | GCC_WARN_UNUSED_VARIABLE = YES; 330 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 331 | MTL_ENABLE_DEBUG_INFO = YES; 332 | ONLY_ACTIVE_ARCH = YES; 333 | SDKROOT = iphoneos; 334 | }; 335 | name = Debug; 336 | }; 337 | 1DD4F52E1DDC676600F0D6B0 /* Release */ = { 338 | isa = XCBuildConfiguration; 339 | buildSettings = { 340 | ALWAYS_SEARCH_USER_PATHS = NO; 341 | CLANG_ANALYZER_NONNULL = YES; 342 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 343 | CLANG_CXX_LIBRARY = "libc++"; 344 | CLANG_ENABLE_MODULES = YES; 345 | CLANG_ENABLE_OBJC_ARC = YES; 346 | CLANG_WARN_BOOL_CONVERSION = YES; 347 | CLANG_WARN_CONSTANT_CONVERSION = YES; 348 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 349 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 350 | CLANG_WARN_EMPTY_BODY = YES; 351 | CLANG_WARN_ENUM_CONVERSION = YES; 352 | CLANG_WARN_INFINITE_RECURSION = YES; 353 | CLANG_WARN_INT_CONVERSION = YES; 354 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 355 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 356 | CLANG_WARN_UNREACHABLE_CODE = YES; 357 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 358 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 359 | COPY_PHASE_STRIP = NO; 360 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 361 | ENABLE_NS_ASSERTIONS = NO; 362 | ENABLE_STRICT_OBJC_MSGSEND = YES; 363 | FRAMEWORK_SEARCH_PATHS = ""; 364 | GCC_C_LANGUAGE_STANDARD = gnu99; 365 | GCC_NO_COMMON_BLOCKS = YES; 366 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 367 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 368 | GCC_WARN_UNDECLARED_SELECTOR = YES; 369 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 370 | GCC_WARN_UNUSED_FUNCTION = YES; 371 | GCC_WARN_UNUSED_VARIABLE = YES; 372 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 373 | MTL_ENABLE_DEBUG_INFO = NO; 374 | SDKROOT = iphoneos; 375 | VALIDATE_PRODUCT = YES; 376 | }; 377 | name = Release; 378 | }; 379 | 1DD4F5301DDC676600F0D6B0 /* Debug */ = { 380 | isa = XCBuildConfiguration; 381 | buildSettings = { 382 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 383 | CODE_SIGN_IDENTITY = "iPhone Developer"; 384 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 385 | CODE_SIGN_STYLE = Automatic; 386 | DEVELOPMENT_TEAM = AA4YKUFB2C; 387 | FRAMEWORK_SEARCH_PATHS = "$(PLATFORM_DIR)/Developer/Library/Frameworks"; 388 | INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; 389 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 390 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 391 | PRODUCT_BUNDLE_IDENTIFIER = s.PureCamerademo; 392 | PRODUCT_NAME = "$(TARGET_NAME)"; 393 | PROVISIONING_PROFILE_SPECIFIER = ""; 394 | }; 395 | name = Debug; 396 | }; 397 | 1DD4F5311DDC676600F0D6B0 /* Release */ = { 398 | isa = XCBuildConfiguration; 399 | buildSettings = { 400 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 401 | CODE_SIGN_IDENTITY = "iPhone Developer"; 402 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 403 | CODE_SIGN_STYLE = Automatic; 404 | DEVELOPMENT_TEAM = AA4YKUFB2C; 405 | FRAMEWORK_SEARCH_PATHS = "$(PLATFORM_DIR)/Developer/Library/Frameworks"; 406 | INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; 407 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 408 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 409 | PRODUCT_BUNDLE_IDENTIFIER = s.PureCamerademo; 410 | PRODUCT_NAME = "$(TARGET_NAME)"; 411 | PROVISIONING_PROFILE_SPECIFIER = ""; 412 | }; 413 | name = Release; 414 | }; 415 | /* End XCBuildConfiguration section */ 416 | 417 | /* Begin XCConfigurationList section */ 418 | 1DD4F4FD1DDC676600F0D6B0 /* Build configuration list for PBXProject "PureCamerademo" */ = { 419 | isa = XCConfigurationList; 420 | buildConfigurations = ( 421 | 1DD4F52D1DDC676600F0D6B0 /* Debug */, 422 | 1DD4F52E1DDC676600F0D6B0 /* Release */, 423 | ); 424 | defaultConfigurationIsVisible = 0; 425 | defaultConfigurationName = Release; 426 | }; 427 | 1DD4F52F1DDC676600F0D6B0 /* Build configuration list for PBXNativeTarget "PureCamerademo" */ = { 428 | isa = XCConfigurationList; 429 | buildConfigurations = ( 430 | 1DD4F5301DDC676600F0D6B0 /* Debug */, 431 | 1DD4F5311DDC676600F0D6B0 /* Release */, 432 | ); 433 | defaultConfigurationIsVisible = 0; 434 | defaultConfigurationName = Release; 435 | }; 436 | /* End XCConfigurationList section */ 437 | }; 438 | rootObject = 1DD4F4FA1DDC676600F0D6B0 /* Project object */; 439 | } 440 | -------------------------------------------------------------------------------- /PureCamerademo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PureCamerademo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /PureCamerademo.xcodeproj/project.xcworkspace/xcuserdata/shiyue.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wubianxiaoxian/PureCamera-Demo/31a8a0970774561ceab0b29c7829388ee802f992/PureCamerademo.xcodeproj/project.xcworkspace/xcuserdata/shiyue.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /PureCamerademo.xcodeproj/project.xcworkspace/xcuserdata/sunkaifeng.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wubianxiaoxian/PureCamera-Demo/31a8a0970774561ceab0b29c7829388ee802f992/PureCamerademo.xcodeproj/project.xcworkspace/xcuserdata/sunkaifeng.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /PureCamerademo.xcodeproj/xcuserdata/shiyue.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /PureCamerademo.xcodeproj/xcuserdata/shiyue.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | PureCamerademo.xcscheme 8 | 9 | isShown 10 | 11 | orderHint 12 | 1 13 | 14 | 15 | SuppressBuildableAutocreation 16 | 17 | 1DD4F5011DDC676600F0D6B0 18 | 19 | primary 20 | 21 | 22 | 1DD4F51A1DDC676600F0D6B0 23 | 24 | primary 25 | 26 | 27 | 1DD4F5251DDC676600F0D6B0 28 | 29 | primary 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /PureCamerademo.xcodeproj/xcuserdata/sunkaifeng.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 14 | 15 | 16 | 18 | 24 | 25 | 26 | 27 | 28 | 30 | 42 | 43 | 44 | 46 | 58 | 59 | 60 | 62 | 74 | 75 | 76 | 78 | 90 | 91 | 92 | 94 | 106 | 107 | 108 | 110 | 122 | 123 | 124 | 126 | 138 | 139 | 140 | 142 | 154 | 155 | 156 | 158 | 170 | 171 | 172 | 174 | 186 | 187 | 188 | 190 | 202 | 203 | 204 | 206 | 218 | 219 | 220 | 222 | 234 | 235 | 236 | 238 | 250 | 251 | 252 | 254 | 266 | 267 | 268 | 270 | 282 | 283 | 284 | 286 | 298 | 299 | 300 | 302 | 314 | 315 | 316 | 318 | 330 | 331 | 332 | 334 | 346 | 347 | 348 | 350 | 362 | 363 | 364 | 366 | 378 | 379 | 380 | 382 | 394 | 395 | 396 | 398 | 410 | 411 | 412 | 414 | 426 | 427 | 428 | 430 | 442 | 443 | 444 | 446 | 458 | 459 | 460 | 462 | 474 | 475 | 476 | 478 | 490 | 491 | 492 | 494 | 506 | 507 | 508 | 510 | 522 | 523 | 524 | 526 | 538 | 539 | 540 | 542 | 554 | 555 | 556 | 558 | 570 | 571 | 572 | 574 | 586 | 587 | 588 | 590 | 602 | 603 | 604 | 606 | 618 | 619 | 620 | 621 | 622 | -------------------------------------------------------------------------------- /PureCamerademo.xcodeproj/xcuserdata/sunkaifeng.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | PureCamerademo.xcscheme 8 | 9 | orderHint 10 | 1 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 1DD4F5011DDC676600F0D6B0 16 | 17 | primary 18 | 19 | 20 | 1DD4F51A1DDC676600F0D6B0 21 | 22 | primary 23 | 24 | 25 | 1DD4F5251DDC676600F0D6B0 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /PureCamerademo/PureCamerademo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // PureCamerademo 4 | // 5 | // Created by 孙凯峰 on 2016/11/16. 6 | // Copyright © 2016年 孙凯峰. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /PureCamerademo/PureCamerademo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // PureCamerademo 4 | // 5 | // Created by 孙凯峰 on 2016/11/16. 6 | // Copyright © 2016年 孙凯峰. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // 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. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // 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. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // 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. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /PureCamerademo/PureCamerademo/Assets.xcassets/1.imageset/C8AECEE3EC242CAA4442358F3D912F9A.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wubianxiaoxian/PureCamera-Demo/31a8a0970774561ceab0b29c7829388ee802f992/PureCamerademo/PureCamerademo/Assets.xcassets/1.imageset/C8AECEE3EC242CAA4442358F3D912F9A.jpg -------------------------------------------------------------------------------- /PureCamerademo/PureCamerademo/Assets.xcassets/1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "C8AECEE3EC242CAA4442358F3D912F9A.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PureCamerademo/PureCamerademo/Assets.xcassets/2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "FE00349D152834B01E38D3F64A9D1217.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /PureCamerademo/PureCamerademo/Assets.xcassets/2.imageset/FE00349D152834B01E38D3F64A9D1217.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wubianxiaoxian/PureCamera-Demo/31a8a0970774561ceab0b29c7829388ee802f992/PureCamerademo/PureCamerademo/Assets.xcassets/2.imageset/FE00349D152834B01E38D3F64A9D1217.jpg -------------------------------------------------------------------------------- /PureCamerademo/PureCamerademo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | } 43 | ], 44 | "info" : { 45 | "version" : 1, 46 | "author" : "xcode" 47 | } 48 | } -------------------------------------------------------------------------------- /PureCamerademo/PureCamerademo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /PureCamerademo/PureCamerademo/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 | -------------------------------------------------------------------------------- /PureCamerademo/PureCamerademo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 29 | 30 | 31 | 32 | 33 | 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 | -------------------------------------------------------------------------------- /PureCamerademo/PureCamerademo/KModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // KModel.h 3 | // PureCamerademo 4 | // 5 | // Created by 五月 on 2018/3/23. 6 | // Copyright © 2018年 五月. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface KModel : NSObject 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /PureCamerademo/PureCamerademo/KModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // KModel.m 3 | // PureCamerademo 4 | // 5 | // Created by 五月 on 2018/3/23. 6 | // Copyright © 2018年 五月. All rights reserved. 7 | // 8 | 9 | #import "KModel.h" 10 | 11 | @implementation KModel 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /PureCamerademo/PureCamerademo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // PureCamerademo 4 | // 5 | // Created by 孙凯峰 on 2016/11/16. 6 | // Copyright © 2016年 孙凯峰. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /PureCamerademo/PureCamerademo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // PureCamerademo 4 | // 5 | // Created by 孙凯峰 on 2016/11/16. 6 | // Copyright © 2016年 孙凯峰. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "PureCamera.h" 11 | #import "TOCropViewController.h" 12 | #import "PureCropVC.h" 13 | @interface ViewController () 14 | 15 | - (IBAction)pushCameraclick:(id)sender; 16 | @property (weak, nonatomic) IBOutlet UIImageView *Kimageview; 17 | - (IBAction)pushCropClick:(id)sender; 18 | @property (weak, nonatomic) IBOutlet UIImageView *cropImageview; 19 | 20 | @end 21 | 22 | @implementation ViewController 23 | 24 | - (void)viewDidLoad { 25 | [super viewDidLoad]; 26 | } 27 | 28 | 29 | - (void)didReceiveMemoryWarning { 30 | [super didReceiveMemoryWarning]; 31 | // Dispose of any resources that can be recreated. 32 | } 33 | 34 | - (IBAction)pushCameraclick:(id)sender { 35 | if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { 36 | PureCamera *homec = [[PureCamera alloc] init]; 37 | __weak typeof(self) myself = self; 38 | homec.fininshcapture = ^(UIImage *ss) { 39 | if (ss) { 40 | NSLog(@"照片存在"); 41 | myself.Kimageview.image = ss; 42 | } 43 | }; 44 | [myself presentViewController:homec 45 | animated:NO 46 | completion:^{ 47 | }]; 48 | } else { 49 | NSLog(@"相机调用失败"); 50 | } 51 | } 52 | - (IBAction)pushCropClick:(id)sender { 53 | // self.cropImageview.image 54 | 55 | PureCropVC *vc = [[PureCropVC alloc]initWithImage:self.cropImageview.image aspectRatioStle:TOCropViewControllerAspectRatioSquare]; 56 | vc.delegate = self; 57 | 58 | [self presentViewController:vc animated:YES completion:nil]; 59 | } 60 | - (void)cropViewController:(TOCropViewController *)cropViewController 61 | didCropToImage:(UIImage *)image 62 | withRect:(CGRect)cropRect 63 | angle:(NSInteger)angle { 64 | 65 | self.cropImageview.image = image; 66 | self.navigationItem.rightBarButtonItem.enabled = YES; 67 | CGRect viewFrame = [self.view convertRect:self.cropImageview.frame toView:self.navigationController.view]; 68 | [cropViewController dismissAnimatedFromParentViewController:self 69 | withCroppedImage:image 70 | toFrame:viewFrame 71 | completion:^{ 72 | }]; 73 | NSLog(@"最后"); 74 | } 75 | @end 76 | -------------------------------------------------------------------------------- /PureCamerademo/PureCamerademo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // PureCamerademo 4 | // 5 | // Created by 孙凯峰 on 2016/11/16. 6 | // Copyright © 2016年 孙凯峰. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PureCamera 2 | = 3 | 4 | 5 | [![CI Status](http://img.shields.io/travis/wubianxiaoxian/PureCamera.svg?style=flat)](https://travis-ci.org/wubianxiaoxian/PureCamera) 6 | [![Version](https://img.shields.io/cocoapods/v/PureCamera.svg?style=flat)](http://cocoapods.org/pods/PureCamera) 7 | [![License](https://img.shields.io/cocoapods/l/PureCamera.svg?style=flat)](http://cocoapods.org/pods/PureCamera) 8 | [![Platform](https://img.shields.io/cocoapods/p/PureCamera.svg?style=flat)](http://cocoapods.org/pods/PureCamera) 9 | 10 | 11 | 12 | A custom camera that allows for free cropping of photos upon completion 13 | ---- 14 | 15 | Requirements 16 | ---- 17 | 18 | * Xcode 8 or higher 19 | * iOS 8.0 or higher 20 | * ARC 21 | 22 | Version 23 | ---- 24 | 25 | * 1.6.3 26 | 27 | Usage 28 | ---- 29 | 30 | * Installation with CocoaPods: pod 'PureCamera', import 31 | 32 | ```objc 33 | #import 34 | ``` 35 | 36 | * Or download the demo locally and add PureCamera to your project, import 37 | 38 | ```objc 39 | #import "PureCamera.h" 40 | ``` 41 | 42 | * Add the following to info.plist 43 | 44 | ```objc 45 | Privacy - Camera Usage Description Use camera 46 | ``` 47 | 48 | * Use the following method to call the camera 49 | 50 | ```objc 51 | PureCamera *homec=[[PureCamera alloc]init]; 52 | __weak typeof(self)myself=self; 53 | homec.fininshcapture=^(UIImage *ss){ 54 | if (ss) { 55 | NSLog(@"Photo exists"); 56 | //Here you can get the cropped photo 57 | myself.ViewImageview.image=ss; 58 | } 59 | } ; 60 | [self presentViewController:homec animated:NO completion:^{}];} 61 | ``` 62 | 63 | * Use the following method to call the image cropping page 64 | 65 | ```objc 66 | First import #import "TOCropViewController.h" 67 | Adhere to @interface ViewController() 68 | Pass in an image and you can present the image cropping page 69 | 70 | TOCropViewController *cropController = [[TOCropViewController alloc] initWithImage:self.cropImageview.image]; 71 | cropController.delegate = self; 72 | [self presentViewController:cropController animated:YES completion:nil]; 73 | 74 | - (void)cropViewController:(TOCropViewController *)cropViewController didCropToImage:(UIImage *)image withRect:(CGRect)cropRect angle:(NSInteger)angle 75 | { 76 | self.cropImageview.image=image; 77 | self.navigationItem.rightBarButtonItem.enabled = YES; 78 | //The following defines an animation effect, which is that when the image cropping page disappears, it will use the frame of the view you defined as the boundary after the disappearance. 79 | CGRect viewFrame = [self.view convertRect:self.cropImageview.frame toView:self.navigationController.view]; 80 | [cropViewController dismissAnimatedFromParentViewController:self withCroppedImage:image toFrame:viewFrame completion:^{ 81 | }]; 82 | } 83 | ``` 84 | 85 | 86 | ![skfcamera相机录制gifnew.gif](http://upload-images.jianshu.io/upload_images/964698-c4869c9a7c92ae25.gif?imageMogr2/auto-orient/strip) 87 | 88 | If you encounter any problems during use, please feel free to submit an issue. 89 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # Build, test, and archive an Xcode workspace on macOS. 3 | # Add steps that install certificates, test, sign, and distribute an app, save build artifacts, and more: 4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/xcode 5 | 6 | trigger: 7 | - master 8 | 9 | pool: 10 | vmImage: 'macos-latest' 11 | 12 | steps: 13 | - task: Xcode@5 14 | inputs: 15 | actions: 'build' 16 | scheme: '' 17 | sdk: 'iphoneos' 18 | configuration: 'Release' 19 | xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace' 20 | xcodeVersion: 'default' # Options: 8, 9, 10, default, specifyPath 21 | --------------------------------------------------------------------------------