一行代碼搞定圖片選擇 // // gzhPhotoManager.h // 圖片選擇 // // Created by 郭志賀 on 2020/5/26. // Copyright © 2020 郭志賀. All rights reserved. // #import <Foundation/Fou ...
一行代碼搞定圖片選擇
// // gzhPhotoManager.h // 圖片選擇 // // Created by 郭志賀 on 2020/5/26. // Copyright © 2020 郭志賀. All rights reserved. // #import <Foundation/Foundation.h> #import "ViewController.h" NS_ASSUME_NONNULL_BEGIN @protocol gzhPhotoManagerDelegate; @interface gzhPhotoManager : NSObject +(instancetype)instance; /// 選擇圖片 /// @param controller 當前控制器 /// @param target 代理 /// @param pSize 選擇照片尺寸 尺寸傳(0,0)不進行裁剪 - (void)selectPhotoWithController:(UIViewController *)controller delegate:(id)target size:(CGSize)pSize; @end @protocol gzhPhotoManagerDelegate <NSObject> - (void)selectedPhotoImage:(UIImage *)image; @end NS_ASSUME_NONNULL_END
1 // 2 // gzhPhotoManager.m 3 // 圖片選擇 4 // 5 // Created by 郭志賀 on 2020/5/26. 6 // Copyright © 2020 郭志賀. All rights reserved. 7 // 8 9 #import "gzhPhotoManager.h" 10 #import <MobileCoreServices/MobileCoreServices.h> 11 #import <Photos/Photos.h> 12 #import <AssetsLibrary/AssetsLibrary.h> 13 #import <MetalPerformanceShaders/MetalPerformanceShaders.h> 14 15 @interface gzhPhotoManager () <UINavigationControllerDelegate,UIImagePickerControllerDelegate> 16 17 @property (nonatomic, weak) id<gzhPhotoManagerDelegate> delegate; 18 @property (nonatomic, assign) CGSize photoSize; 19 @property (nonatomic, strong) UIImage *image; 20 @property (nonatomic, weak) UIViewController *controller; 21 @property (nonatomic, strong) UIImagePickerController *imagePickerController; 22 23 @end 24 25 26 @implementation gzhPhotoManager 27 28 + (instancetype)instance { 29 static gzhPhotoManager * shareInstance = nil; 30 static dispatch_once_t onceToken; 31 dispatch_once(&onceToken, ^{ 32 shareInstance = [[gzhPhotoManager alloc]init]; 33 }); 34 return shareInstance; 35 } 36 -(void)selectPhotoWithController:(UIViewController *)controller delegate:(id)target size:(CGSize)pSize{ 37 38 _controller = controller; 39 _delegate = target; 40 _photoSize = pSize; 41 42 UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet]; 43 [alertVC addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]]; 44 [alertVC addAction:[UIAlertAction actionWithTitle:@"拍照" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 45 46 [self cameraCheck:action]; 47 }]]; 48 [alertVC addAction:[UIAlertAction actionWithTitle:@"從手機相冊中選擇" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 49 50 [self phAuthorizationCheck:action]; 51 }]]; 52 [_controller presentViewController:alertVC animated:YES completion:nil]; 53 } 54 -(void)cameraCheck:(UIAlertAction *)action{ 55 /* 56 AVAuthorizationStatusNotDetermined = 0,// 系統還未知是否訪問,第一次開啟相機時 57 58 AVAuthorizationStatusRestricted, // 受限制的 59 60 AVAuthorizationStatusDenied, //不允許 61 62 AVAuthorizationStatusAuthorized // 允許狀態 63 */ 64 65 ALAuthorizationStatus author =[ALAssetsLibrary authorizationStatus]; 66 if (author == AVAuthorizationStatusRestricted || author ==AVAuthorizationStatusDenied) { 67 [self alertViewWithTitle:@"提示" message:@"如需拍照,請檢查拍照功能是否開啟,可在:設置->隱私->照相.設置"]; 68 }else if (author == AVAuthorizationStatusAuthorized){ 69 [self selectCamera:action]; 70 }else if (author == AVAuthorizationStatusNotDetermined){ 71 [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { 72 73 if (granted) { 74 75 //允許訪問 76 [self selectCamera:action]; 77 }else{ 78 79 //不允許訪問 80 [self alertViewWithTitle:@"提示" message:@"如需拍照,請檢查拍照功能是否開啟,可在:設置->隱私->照相.設置"]; 81 } 82 83 }]; 84 } 85 86 87 } 88 89 //判斷是否有許可權訪問相簿 90 - (void)phAuthorizationCheck:(UIAlertAction *)action{ 91 /* 92 PHAuthorizationStatusNotDetermined, 用戶還沒有做出選擇 93 PHAuthorizationStatusDenied, 用戶拒絕當前應用訪問相冊(用戶當初點擊了"不允許") 94 PHAuthorizationStatusAuthorized 用戶允許當前應用訪問相冊(用戶當初點擊了"好") 95 PHAuthorizationStatusRestricted, 因為家長控制, 導致應用無法方法相冊(跟用戶的選擇沒有關係) 96 */ 97 98 // 判斷授權狀態 99 PHAuthorizationStatus statu = [PHPhotoLibrary authorizationStatus]; 100 if (statu == PHAuthorizationStatusRestricted) { 101 NSLog(@"無法訪問相簿--PHAuthorizationStatusRestricted"); 102 [self alertViewWithTitle:@"提示" message:@"如需拍照,請檢查拍照功能是否開啟,可在:設置->隱私->照片.設置"]; 103 } else if (statu == PHAuthorizationStatusDenied) { 104 NSLog(@"無法訪問相簿--PHAuthorizationStatusDenied"); 105 [self alertViewWithTitle:@"提示" message:@"如需拍照,請檢查拍照功能是否開啟,可在:設置->隱私->照片.設置"]; 106 } else if (statu == PHAuthorizationStatusAuthorized) { 107 NSLog(@"可以訪問相簿--PHAuthorizationStatusAuthorized"); 108 [self selectPhotoLibrary:action]; 109 } else if (statu == PHAuthorizationStatusNotDetermined) { 110 // 彈框請求用戶授權 111 NSLog(@"第一次訪問--PHAuthorizationStatusNotDetermined"); 112 [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { 113 114 if (status == PHAuthorizationStatusAuthorized) { 115 [self selectPhotoLibrary:action]; 116 }else{ 117 [self alertViewWithTitle:@"提示" message:@"如需拍照,請檢查拍照功能是否開啟,可在:設置->隱私->照片.設置"]; 118 } 119 120 }]; 121 122 } 123 124 125 } 126 // 拍照 127 - (void)selectCamera:(UIAlertAction *)action { 128 if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { 129 dispatch_async(dispatch_get_main_queue(), ^{ 130 [self alertViewWithTitle:@"警告" message:@"對不起,您的設備不存在相機"]; 131 }); 132 133 return; 134 } 135 136 137 if (!_imagePickerController) { 138 _imagePickerController = [UIImagePickerController new]; 139 _imagePickerController.delegate = self; 140 } 141 if (_photoSize.width!=0&&_photoSize.height!=0) { 142 _imagePickerController.allowsEditing = YES; 143 }else{ 144 _imagePickerController.allowsEditing = NO; 145 } 146 147 _imagePickerController.mediaTypes = @[(NSString *)kUTTypeImage]; 148 _imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera; 149 _imagePickerController.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto; 150 [_controller presentViewController:_imagePickerController animated:YES completion:nil]; 151 } 152 153 // 從相冊中選擇 154 - (void)selectPhotoLibrary:(UIAlertAction *)action { 155 if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) { 156 dispatch_async(dispatch_get_main_queue(), ^{ 157 [self alertViewWithTitle:@"警告" message:@"對不起,您的設備不存在相冊"]; 158 }); 159 160 } 161 if (!_imagePickerController) { 162 _imagePickerController = [UIImagePickerController new]; 163 _imagePickerController.delegate = self; 164 } 165 if (_photoSize.width!=0&&_photoSize.height!=0) { 166 _imagePickerController.allowsEditing = YES; 167 }else{ 168 _imagePickerController.allowsEditing = NO; 169 } 170 _imagePickerController.mediaTypes = @[(NSString *)kUTTypeImage,(NSString *)kUTTypeMovie]; 171 _imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; 172 [_controller presentViewController:_imagePickerController animated:YES completion:nil]; 173 174 175 176 } 177 #pragma mark - 178 #pragma mark - UIImagePickerViewController delegate 179 - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { 180 181 NSString * mediaType = [info objectForKey:UIImagePickerControllerMediaType]; 182 if ([mediaType isEqualToString:(NSString *)kUTTypeImage]){ 183 if (_photoSize.height!=0&&_photoSize.width!=0) { 184 UIImage *image = [self fixOrientation:[info objectForKey:UIImagePickerControllerEditedImage]]; 185 self.image = [self scaleImage:image Tosize:self.photoSize]; 186 if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) { 187 UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil); 188 } 189 }else{ 190 UIImage *image = [self fixOrientation:[info objectForKey:UIImagePickerControllerOriginalImage]]; 191 self.image = [self scaleImage:image Tosize:self.photoSize]; 192 if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) { 193 UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil); 194 } 195 } 196 [picker dismissViewControllerAnimated:YES completion:^{ 197 if (self.delegate && [self.delegate respondsToSelector:@selector(selectedPhotoImage:)]) { 198 if (self.image) { 199 [self.delegate selectedPhotoImage:self.image]; 200 } else { 201 [self alertViewWithTitle:@"你還沒選擇圖片呢" message:nil]; 202 } 203 } 204 }]; 205 } 206 207 208 } 209 210 -(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{ 211 [picker dismissViewControllerAnimated:YES completion:nil]; 212 } 213 // 裁剪圖片 214 - (UIImage *)scaleImage:(UIImage *)img Tosize:(CGSize)size { 215 216 CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width; 217 CGSize imgSize = CGSizeMake(0, 0); 218 if (size.width != 0 && size.height != 0) { 219 imgSize = CGSizeMake(size.width, img.size.height*(size.width/img.size.width)); 220 } else { 221 imgSize = CGSizeMake(screenWidth*2, img.size.height*(screenWidth/img.size.width)*2); 222 } 223 // 創建一個bitmap的context 224 // 並把它設置成為當前正在使用的context 225 UIGraphicsBeginImageContext(imgSize); 226 // 繪製改變大小的圖片 227 [img drawInRect:CGRectMake(0, 0, imgSize.width, imgSize.height)]; 228 // 從當前context中創建一個改變大小後的圖片 229 UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext(); 230 // 使當前的context出堆棧 231 UIGraphicsEndImageContext(); 232 //返回新的改變大小後的圖片 233 return scaledImage; 234 } 235 236 237 //修正image方向 238 - (UIImage *)fixOrientation:(UIImage *)aImage { 239 240 241 if (aImage.imageOrientation == UIImageOrientationUp) 242 return aImage; 243 244 CGAffineTransform transform = CGAffineTransformIdentity; 245 246 switch (aImage.imageOrientation) { 247 case UIImageOrientationDown: 248 case UIImageOrientationDownMirrored: 249 transform = CGAffineTransformTranslate(transform, aImage.size.width, aImage.size.height); 250 transform = CGAffineTransformRotate(transform, M_PI); 251 break; 252 253 case UIImageOrientationLeft: 254 case UIImageOrientationLeftMirrored: 255 transform = CGAffineTransformTranslate(transform, aImage.size.width, 0); 256 transform = CGAffineTransformRotate(transform, M_PI_2); 257 break; 258 259 case UIImageOrientationRight: 260 case UIImageOrientationRightMirrored: 261 transform = CGAffineTransformTranslate(transform, 0, aImage.size.height); 262 transform = CGAffineTransformRotate(transform, -M_PI_2); 263 break; 264 default: 265 break; 266 } 267 268 switch (aImage.imageOrientation) { 269 case UIImageOrientationUpMirrored: 270 case UIImageOrientationDownMirrored: 271 transform = CGAffineTransformTranslate(transform, aImage.size.width, 0); 272 transform = CGAffineTransformScale(transform, -1, 1); 273 break; 274 275 case UIImageOrientationLeftMirrored: 276 case UIImageOrientationRightMirrored: 277 transform = CGAffineTransformTranslate(transform, aImage.size.height, 0); 278 transform = CGAffineTransformScale(transform, -1, 1); 279 break; 280 default: 281 break; 282 } 283 284 CGContextRef ctx = CGBitmapContextCreate(NULL, aImage.size.width, aImage.size.height, 285 CGImageGetBitsPerComponent(aImage.CGImage), 0, 286 CGImageGetColorSpace(aImage.CGImage), 287 CGImageGetBitmapInfo(aImage.CGImage)); 288 CGContextConcatCTM(ctx, transform); 289 switch (aImage.imageOrientation) { 290 case UIImageOrientationLeft: 291 case UIImageOrientationLeftMirrored: 292 case UIImageOrientationRight: 293 case UIImageOrientationRightMirrored: 294 // Grr... 295 CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.height,aImage.size.width), aImage.CGImage); 296 break; 297 298 default: 299 CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.width,aImage.size.height), aImage.CGImage); 300 break; 301 } 302 303 // And now we just create a new UIImage from the drawing context 304 CGImageRef cgimg = CGBitmapContextCreateImage(ctx); 305 UIImage *img = [UIImage imageWithCGImage:cgimg]; 306 CGContextRelease(ctx); 307 CGImageRelease(cgimg); 308 return img; 309 } 310 311 312 // 提醒 313 - (void)alertViewWithTitle:(NSString *)title message:(NSString *)msg { 314 UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert]; 315 [alertVC addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]]; 316 [_controller presentViewController:alertVC animated:YES completion:nil]; 317 } 318 319 320 @end
在需要使用的地方遵循<gzhPhotoManagerDelegate>協議
1 // 2 // ViewController.m 3 // 圖片選擇 4 // 5 // Created by 郭志賀 on 2020/5/26. 6 // Copyright © 2020 郭志賀. All rights reserved. 7 // 8 9 #import "ViewController.h" 10 #import "gzhPhotoManager.h" 11 12 /** 屏幕高度 */ 13 #define ScreenH [UIScreen mainScreen].bounds.size.height 14 /** 屏幕寬度 */ 15 #define ScreenW [UIScreen mainScreen].bounds.size.width 16 17 @interface ViewController ()<gzhPhotoManagerDelegate> 18 @property(nonatomic,strong)UIImageView * selectImageView; 19 @end 20 21 @implementation ViewController 22 23 - (void)viewDidLoad { 24 [super viewDidLoad]; 25 // Do any additional setup after loading the view. 26 27 _selectImageView = [[UIImageView alloc]init]; 28 _selectImageView.frame = CGRectMake(0, 0, ScreenW, ScreenH); 29 _selectImageView.contentMode = UIViewContentModeScaleAspectFit; 30 _selectImageView.clipsToBounds = YES; 31 _selectImageView.backgroundColor = [UIColor purpleColor]; 32 [self.view addSubview:_selectImageView]; 33 34 _selectImageView.userInteractionEnabled = YES; 35 UITapGestureRecognizer * selectPhotoTapGes = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(selectPhoto:)]; 36 [_selectImageView addGestureRecognizer:selectPhotoTapGes]; 37 38 } 39 -(void)selectPhoto:(UITapGestureRecognizer *)taps{ 40 //調用 41 [[gzhPhotoManager instance]selectPhotoWithController:self delegate:self size:CGSizeMake(ScreenW, ScreenW)]; 42 43 } 44 -(void)selectedPhotoImage:(UIImage *)image{ 45 46 _selectImageView.image = image; 47 48 49 } 50 @end
可直接複製使用,新手見解,如有遺漏或不足敬請告知。