前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS 自定义UIImagePickerController

iOS 自定义UIImagePickerController

作者头像
码客说
发布2019-10-22 14:30:18
1.5K0
发布2019-10-22 14:30:18
举报
文章被收录于专栏:码客码客

系统自带UIImagePickerController的用法

调用方式

代码语言:javascript
复制
UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera;
//sourceType = UIImagePickerControllerSourceTypeCamera; //照相机
//sourceType = UIImagePickerControllerSourceTypePhotoLibrary; //图片库
//sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum; //保存的相片
if(self.picker == nil){
    self.picker = [[UIImagePickerController alloc] init];//初始化
    self.picker.delegate = self;
    self.picker.allowsEditing = NO;//设置可编辑
    self.picker.sourceType = sourceType;
}
   
[self presentViewController:self.picker animated:true completion:nil];

回调

代码语言:javascript
复制
//当选择一张图片后进入这里
-(void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
    
    NSString *type = [info objectForKey:UIImagePickerControllerMediaType];
    
    //当选择的类型是图片
    if ([type isEqualToString:@"public.image"]){
        //先把图片转成NSData
        UIImage* image = [info objectForKey:@"UIImagePickerControllerOriginalImage"];
        image = [self fixOrientation:image];
        NSData *data;
        
        data = UIImageJPEGRepresentation(image, 0.5);
        
        NSString * md5Str = [data MD5HexDigest];
        
        //图片保存的路径
        //这里将图片放在沙盒的documents文件夹中
        NSString * DocumentsPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
        NSString * fileName = [NSString stringWithFormat:@"%@.jpg",md5Str];
        //得到选择后沙盒中图片的完整路径
        _filePath = [[NSString alloc]initWithFormat:@"%@/%@",DocumentsPath,fileName];
        //文件管理器
        NSFileManager *fileManager = [NSFileManager defaultManager];
        
        //把刚刚图片转换的data对象拷贝至沙盒中 并保存为image.jpg
        [fileManager createDirectoryAtPath:DocumentsPath withIntermediateDirectories:YES attributes:nil error:nil];
        [fileManager createFileAtPath:_filePath contents:data attributes:nil];
        NSLog(@"文件的路径为:%@",_filePath);
    } 
    
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
    NSLog(@"您取消了选择图片");
    [self.picker dismissViewControllerAnimated:true completion:^{
        
    }];
}

拍照后的图片90度旋转的解决方法

代码语言:javascript
复制
-(UIImage *)fixOrientation:(UIImage *)aImage {
    // No-op if the orientation is already correct
    if (aImage.imageOrientation == UIImageOrientationUp)
        return aImage;
    // 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 (aImage.imageOrientation) {
        case UIImageOrientationDown:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, aImage.size.width, aImage.size.height);
            transform = CGAffineTransformRotate(transform, M_PI);
            break;
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
            transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
            transform = CGAffineTransformRotate(transform, M_PI_2);
            break;
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, 0, aImage.size.height);
            transform = CGAffineTransformRotate(transform, -M_PI_2);
            break;
        default:
            break;
    }
    switch (aImage.imageOrientation) {
        case UIImageOrientationUpMirrored:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, aImage.size.height, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;
        default:
            break;
    }
    
    // Now we draw the underlying CGImage into a new context, applying the transform
    // calculated above.
    CGContextRef ctx = CGBitmapContextCreate(NULL, aImage.size.width, aImage.size.height,
                                             CGImageGetBitsPerComponent(aImage.CGImage), 0,
                                             CGImageGetColorSpace(aImage.CGImage),
                                             CGImageGetBitmapInfo(aImage.CGImage));
    CGContextConcatCTM(ctx, transform);
    switch (aImage.imageOrientation) {
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.height,aImage.size.width), aImage.CGImage);
            break;
        default:
            CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.width,aImage.size.height), aImage.CGImage);
            break;
    }
    
    // And now we just create a new UIImage from the drawing context
    CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
    UIImage *img = [UIImage imageWithCGImage:cgimg];
    CGContextRelease(ctx);
    CGImageRelease(cgimg);
    return img;
}

自定义相机拍照视图

定义变量

代码语言:javascript
复制
//捕获设备,通常是前置摄像头,后置摄像头,麦克风(音频输入)
@property (nonatomic, strong) AVCaptureDevice *device;

//AVCaptureDeviceInput 代表输入设备,他使用AVCaptureDevice 来初始化
@property (nonatomic, strong) AVCaptureDeviceInput *input;

//输出图片
@property (nonatomic ,strong) AVCaptureStillImageOutput *imageOutput;

//session:由他把输入输出结合在一起,并开始启动捕获设备(摄像头)
@property (nonatomic, strong) AVCaptureSession *session;

//图像预览层,实时显示捕获的图像
@property (nonatomic ,strong) AVCaptureVideoPreviewLayer *previewLayer;

@property (weak, nonatomic) IBOutlet UIView *previewView;
@property (weak, nonatomic) IBOutlet UIImageView *showImageView;

设置相机

代码语言:javascript
复制
- (void)cameraDistrict{
    //    AVCaptureDevicePositionBack  后置摄像头
    //    AVCaptureDevicePositionFront 前置摄像头
    self.device = [self cameraWithPosition:AVCaptureDevicePositionBack];
    self.input = [[AVCaptureDeviceInput alloc] initWithDevice:self.device error:nil];
    
    self.imageOutput = [[AVCaptureStillImageOutput alloc] init];
    
    self.session = [[AVCaptureSession alloc] init];
    //     拿到的图像的大小可以自行设定
    //    AVCaptureSessionPreset320x240
    //    AVCaptureSessionPreset352x288
    //    AVCaptureSessionPreset640x480
    //    AVCaptureSessionPreset960x540
    //    AVCaptureSessionPreset1280x720
    //    AVCaptureSessionPreset1920x1080
    //    AVCaptureSessionPreset3840x2160
    self.session.sessionPreset = AVCaptureSessionPreset640x480;
    //输入输出设备结合
    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 = self.previewView.frame;
    self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    [self.previewView.layer addSublayer:self.previewLayer];
    //设备取景开始
    [self.session startRunning];
    if ([_device lockForConfiguration:nil]) {
        //自动闪光灯,
        if ([_device isFlashModeSupported:AVCaptureFlashModeAuto]) {
            [_device setFlashMode:AVCaptureFlashModeAuto];
        }
        //自动白平衡,但是好像一直都进不去
        if ([_device isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeAutoWhiteBalance]) {
            [_device setWhiteBalanceMode:AVCaptureWhiteBalanceModeAutoWhiteBalance];
        }
        [_device unlockForConfiguration];
    }
    
}

- (AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition)position{
    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    for ( AVCaptureDevice *device in devices )
        if ( device.position == position ){
            return device;
        }
    return nil;
}

获取相机图片

代码语言:javascript
复制
- (void)photoBtnDidClick{
    AVCaptureConnection *conntion = [self.imageOutput connectionWithMediaType:AVMediaTypeVideo];
    if (!conntion) {
        NSLog(@"拍照失败!");
        return;
    }
    [self.imageOutput captureStillImageAsynchronouslyFromConnection:conntion completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
        if (imageDataSampleBuffer == nil) {
            return ;
        }
        NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
        self.showImageView.image = [UIImage imageWithData:imageData];
        self.showImageView.hidden = false;
        [self.session stopRunning];
    }];
}

保存照片到相册

代码语言:javascript
复制
#pragma - 保存至相册
- (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 = @"保存图片成功" ;
    }
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"保存图片结果提示"
                                                    message:msg
                                                   delegate:self
                                          cancelButtonTitle:@"确定"
                                          otherButtonTitles:nil];
    [alert show];
}

前后置摄像头的切换

代码语言:javascript
复制
- (void)changeCamera{
     NSUInteger cameraCount = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo] count];
     if (cameraCount > 1) {
         NSError *error;
         //给摄像头的切换添加翻转动画
         CATransition *animation = [CATransition animation];
         animation.duration = .5f;
         animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
         animation.type = @"oglFlip";
         
         AVCaptureDevice *newCamera = nil;
         AVCaptureDeviceInput *newInput = nil;
         //拿到另外一个摄像头位置
         AVCaptureDevicePosition position = [[_input device] position];
         if (position == AVCaptureDevicePositionFront){
             newCamera = [self cameraWithPosition:AVCaptureDevicePositionBack];
             animation.subtype = kCATransitionFromLeft;//动画翻转方向
         }
         else {
             newCamera = [self cameraWithPosition:AVCaptureDevicePositionFront];
             animation.subtype = kCATransitionFromRight;//动画翻转方向
         }
         //生成新的输入
         newInput = [AVCaptureDeviceInput deviceInputWithDevice:newCamera error:nil];
         [self.previewLayer addAnimation:animation forKey: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);
         }
     }
 }

对焦设置

代码语言:javascript
复制
//AVCaptureFlashMode  闪光灯
//AVCaptureFocusMode  对焦
//AVCaptureExposureMode  曝光
//AVCaptureWhiteBalanceMode  白平衡
//闪光灯和白平衡可以在生成相机时候设置
//曝光要根据对焦点的光线状况而决定,所以和对焦一块写
//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;
//             }];
//         }];
     }
}

遇到的一些坑和解决办法

前后置摄像头的切换

  前后值不能切换,各种尝试找了半天没找到有原因。后来发现我在设置图片尺寸的时候设置为1080P[self.session canSetSessionPreset: AVCaptureSessionPreset1920x1080],前置摄像头并不支持这么大的尺寸,所以就不能切换前置摄像头。   我验证了下 前置摄像头最高支持720P,720P以内可自由切换。 当然也可以在前后置摄像头切换的时候,根据前后摄像头来设置不同的尺寸,这里不在赘述。

焦点位置
代码语言:javascript
复制
CGPoint focusPoint = CGPointMake( point.y /size.height ,1-point.x/size.width );

setExposurePointOfInterest:focusPoint函数后面Point取值范围是取景框左上角(0,0)到取景框右下角(1,1)之间。官方是这么写的:

代码语言:javascript
复制
The value of this property is a CGPoint that determines the receiver's focus point of interest, if it has one. A value of (0,0) indicates that the camera should focus on the top left corner of the image, while a value of (1,1) indicates that it should focus on the bottom right. The default value is (0.5,0.5).
代码语言:javascript
复制
我也试了按这个来但位置就是不对,只能按上面的写法才可以。前面是点击位置的y/PreviewLayer的高度,后面是1-点击位置的x/PreviewLayer的宽度
对焦和曝光

我在设置对焦是 先设置了模式setFocusMode,后设置对焦位置,就会导致很奇怪的现象,对焦位置是你上次点击的位置。所以一定要先设置位置,再设置对焦模式。 曝光同上

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-11-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 系统自带UIImagePickerController的用法
    • 调用方式
      • 回调
        • 拍照后的图片90度旋转的解决方法
        • 自定义相机拍照视图
          • 定义变量
            • 设置相机
              • 获取相机图片
                • 保存照片到相册
                  • 前后置摄像头的切换
                    • 对焦设置
                      • 遇到的一些坑和解决办法
                        • 前后置摄像头的切换
                        • 焦点位置
                        • 对焦和曝光
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档