iOS 拍照

使用系统框架AVFoundation下的:

<AVCapturePhotoCaptureDelegate>进行视频录制与回调

创建LyPhotoCollection继承与UIView

.h

#import <AVFoundation/AVFoundation.h>
#import <Photos/Photos.h>
//回调
@property(nonatomic,copy)void (^photoComesBlack) (UIImage *photoImage);
//拍照
-(void)shutterCamera;
// 闪光灯开关
-(void)lightAction;
//停止运行
-(void)stopRunning;
//开始运行
-(void)startRunning;
/**
 切换前后摄像头
 @param camera 前置、后置
 */
- (void)cameraPosition:(NSString *)camera;
//照片保存到相册
- (void)saveImageWithImage:(UIImage *)image;
//放大缩小屏幕
- (void)viewScaleChnageValue:(CGFloat )sender;

.m

@interface LyPhotoCollection () <AVCapturePhotoCaptureDelegate>
@property (nonatomic, strong) AVCaptureSession *captureSession; // 会话
@property (nonatomic, strong) AVCaptureDevice *captureDevice;   // 输入设备
@property (nonatomic, strong) AVCaptureDeviceInput *captureDeviceInput; // 输入源
@property (nonatomic, strong) AVCapturePhotoOutput *photoOutput;    // 图像输出
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer; // 预览画面
@property (nonatomic, strong) AVCapturePhotoSettings *photoSettings;    // 图像设置
@property (nonatomic, assign) AVCaptureFlashMode mode;
@property (nonatomic, assign) AVCaptureDevicePosition position;
//记录拍照状态
@property(nonatomic,strong)NSString * failuresNumber;
@end

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.failuresNumber = 0;
        // 5. 连接输入与会话
        if ([self.captureSession canAddInput:self.captureDeviceInput]) {
            [self.captureSession addInput:self.captureDeviceInput];
        }
        // 6. 连接输出与会话
        if ([self.captureSession canAddOutput:self.photoOutput]) {
            [self.captureSession addOutput:self.photoOutput];
        }
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive) name:UIApplicationWillEnterForegroundNotification object:nil];
    
    }
    return self;
}

#pragma mark - 监听是否重新进入程序程序
-(void)applicationDidBecomeActive{
    if (self.captureSession.isRunning != YES) {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [self.captureSession startRunning];
        });
    }
}

-(void)layoutSubviews{
    [super layoutSubviews];
    self.previewLayer.frame = self.bounds;
    [self.previewLayer removeFromSuperlayer];
    [self.layer insertSublayer:self.previewLayer atIndex:0];
    [self startRunning];
}

#pragma mark - 开始运行
-(void)startRunning{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        [self.captureSession startRunning];
        self.failuresNumber = @"开始拍照";
    });
}

#pragma mark - 停止运行
-(void)stopRunning{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        [self.captureSession stopRunning];
        self.failuresNumber = @"停止拍照";
    });
}

#pragma mark - 调整焦距
- (void)cameraBackgroundDidChangeFocus:(CGFloat)focus{
    AVCaptureDevice *captureDevice = [self.captureDeviceInput device];
    NSError *error;
    if ([captureDevice lockForConfiguration:&error]) {
        if ([captureDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]){
            [captureDevice setFocusModeLockedWithLensPosition:focus completionHandler:nil];
        }
    }
    else{
        // Handle the error appropriately.
   }
}

#pragma mark - 拍照
-(void)shutterCamera{
    self.photoSettings = [AVCapturePhotoSettings photoSettingsWithFormat:@{AVVideoCodecKey:AVVideoCodecJPEG}];
    [self.photoSettings setFlashMode:self.mode];
    if (!self.previewLayer || !self.photoOutput || !self.photoSettings) {
        return;
    }
    if (self.captureSession.isRunning == YES) {
        [self.photoOutput capturePhotoWithSettings:self.photoSettings delegate:self];
    }
    else{
        if (![self.failuresNumber isEqualToString:@"停止拍照"]) {
            self.failuresNumber = @"拍照失败";
            [self picturesFailed];
        }
        NSLog(@"%@",self.failuresNumber);
    }
}

#pragma mark - 拍照失败重新拍照
-(void)picturesFailed{
    if ([self.failuresNumber isEqualToString:@"拍照失败"]) {
        //     设置一个异步线程组
        dispatch_group_t group = dispatch_group_create();
        dispatch_group_async(group, dispatch_queue_create("com.dispatch.test", DISPATCH_QUEUE_CONCURRENT), ^{
            // 创建一个信号量为0的信号
            dispatch_semaphore_t sema = dispatch_semaphore_create(0);
            //        创建定时器
            dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
            dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC));
            uint64_t interval = (uint64_t)(0.1 * NSEC_PER_SEC);
            dispatch_source_set_timer(timer, start, interval, 0);
            dispatch_source_set_event_handler(timer, ^{
                if (self.captureSession.isRunning == YES) {
                    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                      [self shutterCamera];
                      self.failuresNumber = @"重新拍照完成";
                    });
                    dispatch_semaphore_signal(sema);
                    dispatch_suspend(timer);
                }
            });
            dispatch_resume(timer);
            // 开启信号等待,设置等待时间为永久,直到信号的信号量大于等于1
            dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
        });
    }
}

#pragma mark - 闪光灯开关
-(void)lightAction{
    if (self.mode == AVCaptureFlashModeOn) {
        [self setMode:AVCaptureFlashModeOff];
    } else {
       [self setMode:AVCaptureFlashModeOn];
    }
}


#pragma mark - 切换前后摄像头
- (void)cameraPosition:(NSString *)camera{
    if ([camera isEqualToString:@"前置"]) {
        if (self.captureDevice.position != AVCaptureDevicePositionFront) {
            self.position = AVCaptureDevicePositionFront;
        }
    }
    else if ([camera isEqualToString:@"后置"]){
        if (self.captureDevice.position != AVCaptureDevicePositionBack) {
           self.position = AVCaptureDevicePositionBack;
        }
    }

    AVCaptureDevice * device = [AVCaptureDevice defaultDeviceWithDeviceType:AVCaptureDeviceTypeBuiltInWideAngleCamera mediaType:AVMediaTypeVideo position:self.position];
      if (device) {
        self.captureDevice = device;
        AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:self.captureDevice error:nil];
        [self.captureSession beginConfiguration];
        [self.captureSession removeInput:self.captureDeviceInput];
         if ([self.captureSession canAddInput:input]) {
            [self.captureSession addInput:input];
            self.captureDeviceInput = input;
            [self.captureSession commitConfiguration];
         }
      }
}


#pragma mark - 拍照回调代理
- (void)captureOutput:(AVCapturePhotoOutput *)captureOutput didFinishProcessingPhotoSampleBuffer:(nullable CMSampleBufferRef)photoSampleBuffer previewPhotoSampleBuffer:(nullable CMSampleBufferRef)previewPhotoSampleBuffer resolvedSettings:(AVCaptureResolvedPhotoSettings *)resolvedSettings bracketSettings:(nullable AVCaptureBracketedStillImageSettings *)bracketSettings error:(nullable NSError *)error {
    if (!error) {
        NSData *imageData = [AVCapturePhotoOutput JPEGPhotoDataRepresentationForJPEGSampleBuffer:photoSampleBuffer previewPhotoSampleBuffer:previewPhotoSampleBuffer];
            UIImage *image = [self transfor:[UIImage imageWithData:imageData]];
        if (imageData.length > 0) {
            self.photoComesBlack(image);
        }
    }
    else{
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            self.failuresNumber = @"拍照失败";
            [self picturesFailed];
        });
   }
}

#pragma mark - 解决图片绘制自动旋转90度的问题
-(UIImage *)transfor:(UIImage *)image{
    int destWidth = image.size.width;
    int destHeight = image.size.height;
    UIGraphicsBeginImageContext(CGSizeMake(destWidth, destHeight));
    [image drawInRect:CGRectMake(0,0,destWidth,  destHeight)];
    UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

#pragma mark - 保存图片到相册
- (void)saveImageWithImage:(UIImage *)image{
    //    // 判断授权状态
    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
        if (status != PHAuthorizationStatusAuthorized) return;
        dispatch_async(dispatch_get_main_queue(), ^{
            NSError *error = nil;
            // 保存相片到相机胶卷
            __block PHObjectPlaceholder *createdAsset = nil;
            [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
                createdAsset = [PHAssetCreationRequest creationRequestForAssetFromImage:image].placeholderForCreatedAsset;
           } error:&error];
        
            if (error) {
                NSLog(@"保存失败:%@", error);
                return;
            }
        });
    }];
}

-(NSString *)failuresNumber{
    if (!_failuresNumber) {
        _failuresNumber = [NSString stringWithFormat:@""];
   }
    return _failuresNumber;
}


#pragma mark - 创建会话
-(AVCaptureSession *)captureSession{
    if (!_captureSession) {
        _captureSession = [[AVCaptureSession alloc] init];
        _captureSession.sessionPreset = AVCaptureSessionPresetPhoto; // 画质
    }
    return _captureSession;
}


#pragma mark - 创建输入设备
-(AVCaptureDevice *)captureDevice{
    if (!_captureDevice) {
    //        设置默认前置摄像头
        _captureDevice = [AVCaptureDevice defaultDeviceWithDeviceType:AVCaptureDeviceTypeBuiltInWideAngleCamera mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionFront];
    }
    return _captureDevice;
}


#pragma mark - 创建输入源
-(AVCaptureDeviceInput *)captureDeviceInput{
    if (!_captureDeviceInput) {
        _captureDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:self.captureDevice error:nil];
    }
    return _captureDeviceInput;
}

#pragma mark - 创建图像输出
-(AVCapturePhotoOutput *)photoOutput{
    if (!_photoOutput) {
        _photoOutput = [[AVCapturePhotoOutput alloc] init];
    }
   return _photoOutput;
}

#pragma mark -绘画层
-(AVCaptureVideoPreviewLayer *)previewLayer{
    if (!_previewLayer) {
        _previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.captureSession];
        _previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    }
    return _previewLayer;
}
#pragma mark - 前置和后置摄像头 
-(AVCaptureDevicePosition)position{
    if (!_position) {
       _position = AVCaptureDevicePositionFront;
    }
    return _position;
}

-(void)dealloc{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

猜你喜欢

转载自blog.csdn.net/weixin_34247155/article/details/87117614