最近项目做到用户自定义头像功能模块,然后仿照微信做了一个。从相册获取照片的链接在这:http://blog.csdn.net/a44496913/article/details/72979704

先来两张效果图

1.使用相机拍照

  • 导入需要的框架
#import <AVFoundation/AVFoundation.h>
  • 创建相机
/** 捕获设备,通常是前置摄像头,后置摄像头,麦克风(音频输入) */
@property (strong, nonatomic) AVCaptureDevice *device;/** 代表输入设备,使用AVCaptureDevice初始化 */
@property (strong, nonatomic) AVCaptureDeviceInput *input;/** 输出图片 */
@property (strong, nonatomic) AVCaptureStillImageOutput *imageOutput;/** 由他将输入输出结合在一起,并开始启动捕获设备(摄像头) */
@property (strong, nonatomic) AVCaptureSession *session;/** 图像预览层,实时显示捕获的图像 */
@property (strong, nonatomic) AVCaptureVideoPreviewLayer *previewLayer;
- (void)createCameraDistrict{//获取后置摄像头self.device = [self camerWithPosition:AVCaptureDevicePositionBack];self.input = [[AVCaptureDeviceInput alloc] initWithDevice:self.device error:nil];self.imageOutput = [[AVCaptureStillImageOutput alloc] init];self.session = [[AVCaptureSession alloc] init];//设置获取图片的质量self.session.sessionPreset = AVCaptureSessionPresetPhoto;//添加输入输出if ([self.session canAddInput:self.input]) {[self.session addInput:self.input];}if ([self.session canAddOutput:self.imageOutput]) {[self.session addOutput:self.imageOutput];}//生成预览层self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];self.previewLayer.frame = CGRectMake(0, 35, SCREEN_WIDTH, SCREEN_HEIGHT - self.bottomView.size.height - 35);self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;self.previewLayer.backgroundColor = [UIColor blackColor].CGColor;[self.view.layer addSublayer:self.previewLayer];if ([_device lockForConfiguration:nil]) {//自动闪光灯if ([_device isFlashModeSupported:AVCaptureFlashModeAuto]) {[_device setFlashMode:AVCaptureFlashModeAuto];}//自动白平衡if ([_device isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeAutoWhiteBalance]) {[_device setWhiteBalanceMode:AVCaptureWhiteBalanceModeAutoWhiteBalance];}[_device unlockForConfiguration];}//开始取景[self.session startRunning];
}
//根据前后置位置获取相应的摄像头
- (AVCaptureDevice *)camerWithPosition:(AVCaptureDevicePosition)position{NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];for (AVCaptureDevice *device in devices) {if (device.position == position) {return device;}}return nil;
}
//设置闪光灯状态为自动[self.device lockForConfiguration:nil];if ([self.device hasFlash]) {if ([_device isFlashModeSupported:AVCaptureFlashModeAuto]) {[_device setFlashMode:AVCaptureFlashModeAuto];}}[self.device unlockForConfiguration];
//设置闪光灯状态为打开[self.device lockForConfiguration:nil];if ([self.device hasFlash]) {if ([_device isFlashModeSupported:AVCaptureFlashModeOn]) {[_device setFlashMode:AVCaptureFlashModeOn];}}[self.device unlockForConfiguration];
//设置闪光灯状态为关闭[self.device lockForConfiguration:nil];if ([self.device hasFlash]) {if ([_device isFlashModeSupported:AVCaptureFlashModeOff]) {[_device setFlashMode:AVCaptureFlashModeOff];}}[self.device unlockForConfiguration];
//切换相机
- (IBAction)switchCameraButtonClicked:(id)sender {[self changeCamera];//延迟一秒设置相机初始焦点__weak typeof(self) weakSelf = self;dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC));dispatch_after(delayTime, dispatch_get_main_queue(), ^{[weakSelf setupFocusPointManual]; //设置初始焦点居中});}
- (void)changeCamera{NSUInteger cameraCount = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo] count];if (cameraCount > 1) {NSError *error;//给摄像头的切换添加翻转动画CATransition *animation = [CATransition animation];animation.duration = 0.5f;animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];animation.type = @"oglFlip";animation.subtype = kCATransitionFromLeft;AVCaptureDevice *newCamera = nil;AVCaptureDeviceInput *newInput = nil;//拿到另外一个摄像头位置AVCaptureDevicePosition position = [[_input device] position];if (position == AVCaptureDevicePositionFront){newCamera = [self camerWithPosition:AVCaptureDevicePositionBack];}else {newCamera = [self camerWithPosition:AVCaptureDevicePositionFront];self.lightBtn.selected = YES;[self autoButtonClicked:self.autoBtn];}//生成新的输入newInput = [AVCaptureDeviceInput deviceInputWithDevice:newCamera error:nil];if (newInput != nil) {[self.session beginConfiguration];[self.session removeInput:self.input];if ([self.session canAddInput:newInput]) {[self.session addInput:newInput];self.input = newInput;} else {[self.session addInput:self.input];}[self.session commitConfiguration];} else if (error) {NSLog(@"toggle carema failed, error = %@", error);}[self.previewLayer addAnimation:animation forKey:@"OglFlipAnimation"];}
}
- (void)setupFocusPointManual{CGPoint point = CGPointMake(SCREEN_WIDTH / 2.0, 35 + self.previewLayer.bounds.size.height / 2.0);[self focusAtPoint:point];
}
- (void)focusAtPoint:(CGPoint)point{CGSize size = self.view.bounds.size;CGPoint focusPoint = CGPointMake( point.y /size.height ,1-point.x/size.width );NSError *error;if ([self.device lockForConfiguration:&error]) {if ([self.device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {[self.device setFocusPointOfInterest:focusPoint];[self.device setFocusMode:AVCaptureFocusModeAutoFocus];}if ([self.device isExposureModeSupported:AVCaptureExposureModeAutoExpose ]) {[self.device setExposurePointOfInterest:focusPoint];[self.device setExposureMode:AVCaptureExposureModeAutoExpose];}[self.device unlockForConfiguration];_focusView.center = point;_focusView.hidden = NO;[UIView animateWithDuration:0.3 animations:^{_focusView.transform = CGAffineTransformMakeScale(1.25, 1.25);}completion:^(BOOL finished) {[UIView animateWithDuration:0.5 animations:^{_focusView.transform = CGAffineTransformIdentity;} completion:^(BOOL finished) {_focusView.hidden = YES;}];}];}}
//根据点击手势设置焦点
- (void)focusGesture:(UITapGestureRecognizer*)gesture{CGPoint point = [gesture locationInView:gesture.view];CGRect frame = self.previewLayer.frame;//去除预览区以外的点if ((point.x >= frame.origin.x && point.x <= frame.origin.x + frame.size.width) &&(point.y >= frame.origin.y && point.y <= frame.origin.y + frame.size.height)) {[self focusAtPoint:point];}
}
//拍照、获取照片
- (void)takePhotos{AVCaptureConnection *conntion = [self.imageOutput connectionWithMediaType:AVMediaTypeVideo];if (!conntion) {[YMLPrompt showMessage:@"拍照失败,请重试" delay:3.0f];return;}[self.imageOutput captureStillImageAsynchronouslyFromConnection:conntion completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {if (imageDataSampleBuffer == nil) {return ;}NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];UIImage *image = [UIImage imageWithData:imageData];image = [image fixOrientation]; //修正图片方向[self.session stopRunning];}];}
//获取照片后,保存到相册
- (void)saveImageToPhotoAlbum:(UIImage *)savedImage{UIImageWriteToSavedPhotosAlbum(savedImage, self, @selector(image:didFinishSavingWithError:contextInfo:), NULL);
}//保存完成回调
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo{NSString *msg = nil ;if(error != NULL){msg = @"保存图片失败" ;}else{msg = @"保存图片成功" ;}kLog(@"%@",msg);
}

注意点:1.)由于目前苹果对用户隐私的保护,需要在 Info.plist 文件中添加如下信息:

<key>NSCameraUsageDescription</key>
                     <string>相机使用说明</string>
                     <key>NSPhotoLibraryUsageDescription</key>
                     <string>相册使用说明</string>
               2.) 相机拍照默认是横屏的(Home键在右手侧),拍出来的照片方向不是向上的,在直接预览或者在相册中查看却都是方向向上的,但是在裁剪之后得  到的图片方向不是向上的。通过图片的 imageOrientation 属性可以看到,拍出来的图片方向是 UIImageOrientationRight,所以需要调整图片方向

  • 在UIImage类别中添加一个修正图片方向的方法
#import "UIImage+Custom.h"@implementation UIImage (Custom)- (UIImage *)fixOrientation {// No-op if the orientation is already correctif (self.imageOrientation == UIImageOrientationUp) return self;// We need to calculate the proper transformation to make the image upright.// We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.CGAffineTransform transform = CGAffineTransformIdentity;switch (self.imageOrientation) {case UIImageOrientationDown:case UIImageOrientationDownMirrored:transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height);transform = CGAffineTransformRotate(transform, M_PI);break;case UIImageOrientationLeft:case UIImageOrientationLeftMirrored:transform = CGAffineTransformTranslate(transform, self.size.width, 0);transform = CGAffineTransformRotate(transform, M_PI_2);break;case UIImageOrientationRight:case UIImageOrientationRightMirrored:transform = CGAffineTransformTranslate(transform, 0, self.size.height);transform = CGAffineTransformRotate(transform, -M_PI_2);break;case UIImageOrientationUp:case UIImageOrientationUpMirrored:break;}switch (self.imageOrientation) {case UIImageOrientationUpMirrored:case UIImageOrientationDownMirrored:transform = CGAffineTransformTranslate(transform, self.size.width, 0);transform = CGAffineTransformScale(transform, -1, 1);break;case UIImageOrientationLeftMirrored:case UIImageOrientationRightMirrored:transform = CGAffineTransformTranslate(transform, self.size.height, 0);transform = CGAffineTransformScale(transform, -1, 1);break;case UIImageOrientationUp:case UIImageOrientationDown:case UIImageOrientationLeft:case UIImageOrientationRight:break;}// Now we draw the underlying CGImage into a new context, applying the transform// calculated above.CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height,CGImageGetBitsPerComponent(self.CGImage), 0,CGImageGetColorSpace(self.CGImage),CGImageGetBitmapInfo(self.CGImage));CGContextConcatCTM(ctx, transform);switch (self.imageOrientation) {case UIImageOrientationLeft:case UIImageOrientationLeftMirrored:case UIImageOrientationRight:case UIImageOrientationRightMirrored:// Grr...CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage);break;default:CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage);break;}// And now we just create a new UIImage from the drawing contextCGImageRef cgimg = CGBitmapContextCreateImage(ctx);UIImage *img = [UIImage imageWithCGImage:cgimg];CGContextRelease(ctx);CGImageRelease(cgimg);return img;
}

2.对图片进行裁剪

裁剪图片在 GHPhotoClipView 类中实现

#import <UIKit/UIKit.h>@interface GHPhotoClipView : UIView/** 用于裁剪的原始图片 */
@property (strong, nonatomic) UIImage *image;/** 重新拍照block */
@property (copy, nonatomic) void(^remakeBlock)();/** 裁剪完成block */
@property (copy, nonatomic) void(^sureUseBlock)(UIImage *image);@end
#import "GHPhotoClipView.h"
#import "GHPhotoClipCoverView.h"@interface GHPhotoClipView ()/** 图片 */
@property (strong, nonatomic) UIImageView *imageV;/** 图片加载后的初始位置 */
@property (assign, nonatomic) CGRect norRect;/** 裁剪框frame */
@property (assign, nonatomic) CGRect showRect;@end@implementation GHPhotoClipView- (instancetype)initWithFrame:(CGRect)frame{self = [super initWithFrame:frame];if (self) {self.backgroundColor = [UIColor blackColor];[self createSubViews];}return self;
}- (void)createSubViews{self.imageV = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0 , self.frame.size.width, self.frame.size.width)];[self addSubview:self.imageV];GHPhotoClipCoverView *coverView = [[GHPhotoClipCoverView alloc] initWithFrame:self.bounds];[coverView addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGR:)]];[coverView addGestureRecognizer:[[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinGR:)]];self.showRect = CGRectMake(1, self.frame.size.height * 0.15,self.frame.size.width - 2 ,self.frame.size.width - 2);coverView.showRect = self.showRect;[self addSubview:coverView];UIView *bottomView = [[UIView alloc] initWithFrame:CGRectMake(0, self.frame.size.height - 60, self.frame.size.width, 60)];bottomView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.6f];[coverView addSubview:bottomView];[YMLFactory btnWithFrame:CGRectMake(10, 15, 60, 30) Type:UIButtonTypeCustom Title:@"重拍" fontSize:15 titleColor:[UIColor whiteColor] bgColor:[UIColor clearColor] target:self selector:@selector(leftButtonClicked) superView:bottomView];[YMLFactory btnWithFrame:CGRectMake(bottomView.frame.size.width - 90, 15, 80, 30) Type:UIButtonTypeCustom Title:@"使用照片" fontSize:15 titleColor:[UIColor whiteColor] bgColor:[UIColor clearColor] target:self selector:@selector(rightButtonClicked) superView:bottomView];}- (void)setImage:(UIImage *)image{if (image) {CGFloat ret = image.size.height / image.size.width;_imageV.height = _imageV.width * ret;_imageV.center = self.center;_norRect = _imageV.frame;_imageV.image = image;}_image = image;}- (void)panGR:(UIPanGestureRecognizer *)sender{CGPoint point = [sender translationInView:self];kLog(@"%f %f",point.x,point.y);_imageV.center = CGPointMake(_imageV.centerX + point.x, _imageV.centerY + point.y);[sender setTranslation:CGPointZero inView:self];if (sender.state == UIGestureRecognizerStateEnded) {[UIView animateWithDuration:0.3f animations:^{_imageV.frame = _norRect;}];}
}- (void)pinGR:(UIPinchGestureRecognizer *)sender{_imageV.transform = CGAffineTransformScale(_imageV.transform, sender.scale, sender.scale);sender.scale = 1.0;if (sender.state == UIGestureRecognizerStateEnded) {[UIView animateWithDuration:0.3f animations:^{_imageV.frame = _norRect;}];}
}#pragma mark -- 重拍- (void)leftButtonClicked{kLog(@"重拍");if (self.remakeBlock) {self.remakeBlock();}}#pragma mark -- 使用照片- (void)rightButtonClicked{kLog(@"使用照片");CGFloat w = self.image.size.width;CGFloat h = self.image.size.height;CGFloat originX = (1- self.showRect.size.width / self.norRect.size.width) / 2.0 * w;CGFloat originY = (self.showRect.origin.y - self.norRect.origin.y) / self.norRect.size.height * h;CGFloat clipW = self.showRect.size.width / self.norRect.size.width * w;CGFloat clipH = self.showRect.size.height / self.norRect.size.height * h;CGRect clipRect = CGRectMake(originX, originY, clipW, clipH);UIImage *image = [Tools imageFromImage:self.image inRect:clipRect];_imageV.image = image;if (self.sureUseBlock) {self.sureUseBlock(image);}
}@end
  • 裁剪图片的方法
/*** 从图片中按指定的位置大小截取图片的一部分* UIImage image 原始的图片* CGRect rect 要截取的区域*/
+ (UIImage *)imageFromImage:(UIImage *)image inRect:(CGRect)rect{//将UIImage转换成CGImageRefCGImageRef sourceImageRef = [image CGImage];//按照给定的矩形区域进行剪裁CGImageRef newImageRef = CGImageCreateWithImageInRect(sourceImageRef, rect);//将CGImageRef转换成UIImageUIImage *newImage = [UIImage imageWithCGImage:newImageRef];//返回剪裁后的图片return newImage;
}
  • 裁剪框效果
#import <UIKit/UIKit.h>@interface GHPhotoClipCoverView : UIView/** 显示方框区域 */
@property (assign, nonatomic) CGRect showRect;@end
#import "GHPhotoClipCoverView.h"@implementation GHPhotoClipCoverView- (instancetype)initWithFrame:(CGRect)frame{self = [super initWithFrame:frame];if (self) {self.backgroundColor = [UIColor clearColor];}return self;
}- (void)drawRect:(CGRect)rect{[super drawRect:rect];CGContextRef ctx = UIGraphicsGetCurrentContext();// 整体颜色CGContextSetRGBFillColor(ctx, 0.15, 0.15, 0.15, 0.6);CGContextFillRect(ctx, rect);   //draw the transparent layer//中间清空矩形框CGRect clearDrawRect = self.showRect;CGContextClearRect(ctx, clearDrawRect);//边框CGContextStrokeRect(ctx, clearDrawRect);CGContextSetRGBStrokeColor(ctx, 1, 1, 1, 1);  //颜色CGContextSetLineWidth(ctx, 0.5);             //线宽CGContextAddRect(ctx, clearDrawRect);       //矩形CGContextStrokePath(ctx);
}@end

Demo地址:https://github.com/HuberyYang/CameraDemo.git

参考文章:30分钟搞定iOS自定义相机

如何处理iOS中照片的方向

iOS-AVFoundation自定义相机详解

iOS 相机拍照、相册获取照片(仿微信) 一一 拍照、图片裁剪相关推荐

  1. Android中使用相机和相册获取照片,模仿朋友圈发说说

    话不多说,直接上图,如图: 这个功能相信很多人都会用到,下面来一步一步的设置这个功能. 1:首先布局我们的主界面,这里我使用activity_edit_diary.xml文件来当布局文件: 文件内容如 ...

  2. iOS 从相机或相册获取图片并裁剪

    /load user image - (void)UesrImageClicked { UIActionSheet *sheet; // 判断是否支持相机 if([UIImagePickerContr ...

  3. 用Swift实现iOS相机及相册图片上传

    最近要做一个iOS相机及相册图片上传,其中遇到了这些问题:1.图片增删在UICollectionView里的变化:2.获取相机拍摄的照片和相册的照片:3.将PHAsset对象转为UIImage对象: ...

  4. Xamarin.iOS 相机与相册的基本使用

    本文内容概要:1.调用系统相机和相册获得照片 2.设置选择或者拍照过后调用系统裁剪功能. 3.设置系统相机与相册的语言为中文. 首先是创建了一个UIActionSheet,上面设置了相册与相机还有取消 ...

  5. Android相机、相册获取图片显示并保存到SD卡

    如题,这个需求本不是一个很复杂的过程,但是却存在一些隐患,我也是最近在项目中碰到这个问题,将Android通过相机或相册获取图片并最终显示在界面上做了一个小研究,现将一些结果和附上的一个Demo叙述如 ...

  6. 小米手机从相册获取照片异常,返回空指针异常

    现象: 小米手机MIUI 8 从相册获取照片返回空指针异常 小米手机选择了图片之后,当前Activity会崩掉(别的手机,其他版本都没问题).看异常信息,指示各种空指针异常.也就是说图片路径空了.是u ...

  7. 微信小程序图片裁剪插件image-cropper

    image-cropper 一款高性能的微信小程序图片裁剪插件,支持旋转.设置尺寸 功能亮点 1.支持旋转支持旋转支持旋转. 2.性能超高超流畅,大图毫无卡顿感. 3.可以设置导出图片尺寸. 4.自由 ...

  8. android 微信相册功能,Android仿微信选择图片和拍照功能

    本文实例为大家分享了 Android微信选择图片的具体代码,和微信拍照功能,供大家参考,具体内容如下 1.Android6.0系统,对于权限的使用都是需要申请,选择图片和拍照需要申请Manifest. ...

  9. Android 相机 或者 相册 获取图片裁剪 适用6.0/7.0

    随着Android 的版本更新迭代.本来以前代码很简单的打开相册或者相机  获取图片裁剪 给Unity3D 使用的过程 挺简单的.但是随着 Android 版本的 更新 和 安全 的加强 .有几点 和 ...

最新文章

  1. java 闭包与回调
  2. 图解Java的substring()方法底层干了啥?
  3. Python学习笔记:异步IO(1)
  4. win7系统开启telnet服务器,小编教你win7系统开启Telnet命令的详细教程
  5. python3类与对象汽车,Python3 类与对象
  6. 爬虫用mysql存储还是mongodb_【面试题】Mongodb和MySQL存储爬虫数据的特点是什么?...
  7. 阿里巴巴 连接池 druid 的使用、maven依赖
  8. saltstack中grains简介
  9. 搭建Struts2步骤
  10. springcloud工作笔记096---springboot集成多线程_高并发_集成线程池的使用
  11. 计算机程序试题答案,历年计算机软考程序设计模拟试题及答案
  12. BearPi-IoT串口收发1-普通模式
  13. 泛化误差,偏差方差分解
  14. 代码审计jizhiCMS 后台getshell
  15. office办公软件之ppt视频录制
  16. 已解决pandas创建DataFrame对象失败
  17. android 区分平板,加量不加价!台电首款基于Android 11的平板终上市
  18. apache服务器安装以及使用passenger插件部署rails应用,基于ubuntu 12.04 LTS
  19. n阶奇数魔方阵c语言编程,n阶魔方阵C语言
  20. wince下SD卡驱动开发

热门文章

  1. java 打jar包 (JAR命令)
  2. Android 蓝牙SPP通信——简介
  3. python gps模块_树莓派连接GPS模块
  4. 第八章 云计算原理与技术
  5. 电脑配置检测软件下载
  6. ARP攻击原理与实践
  7. 非全日制毕业的研究生现在怎么样了?
  8. 求职简历撰写要点和模板分享
  9. 10条Linux命令锦囊,防你牢底坐穿
  10. 二级计算机公共基础知识