相機(jī)

https://github.com/starainDou 歡迎點(diǎn)星

拍照方式

拍照大體上有兩種方式:UIImagePickerController方式和AVFoundation方式歼跟,前者簡單易用但是不利于定制和一些復(fù)雜操作,后者反之。

* UIImagePickerController 拍照

屬性、枚舉台夺、代理

@property (nonatomic) UIImagePickerControllerSourceType sourceType;
typedef NS_ENUM(NSInteger, UIImagePickerControllerSourceType) {
    UIImagePickerControllerSourceTypePhotoLibrary,//照片庫
    UIImagePickerControllerSourceTypeCamera,//攝像頭
    UIImagePickerControllerSourceTypeSavedPhotosAlbum//相簿
};
/* 
  媒體類型策幼,默認(rèn)情況下此數(shù)組包含kUTTypeImage,表示拍照
  如果要錄像稻艰,必須設(shè)置為kUTTypeVideo(視頻不帶聲音)或kUTTypeMovie(視頻帶聲音)
*/
@property (nonatomic,copy) NSArray<NSString *> *mediaTypes;
@property (nonatomic) NSTimeInterval videoMaximumDuration;//視頻最大錄制時長扛禽,默認(rèn)10s
@property (nonatomic) UIImagePickerControllerQualityType videoQuality;//視頻質(zhì)量
typedef NS_ENUM(NSInteger, UIImagePickerControllerQualityType) {
    UIImagePickerControllerQualityTypeHigh = 0,  //高清 1920x1080
    UIImagePickerControllerQualityTypeMedium,    //中等锋边,適合WiFi傳輸 568x320
    UIImagePickerControllerQualityTypeLow,      //低質(zhì)量,適合蜂窩網(wǎng)傳輸 224x128
    UIImagePickerControllerQualityType640x480, //640*480
    UIImagePickerControllerQualityTypeIFrame1280x720, //1280*720
    UIImagePickerControllerQualityTypeIFrame960x540, //960*540
};

@property (nonatomic)  BOOL showsCameraControls;/* 是否顯示攝像頭控制面板编曼,默認(rèn)為YES */
@property (nonatomic,strong) UIView *cameraOverlayView;/* 攝像頭上覆蓋的視圖 */
@property (nonatomic) CGAffineTransform cameraViewTransform;/* 攝像頭形變 */

@property (nonatomic) UIImagePickerControllerCameraCaptureMode cameraCaptureMode;/* 攝像頭捕捉模式 */
typedef NS_ENUM(NSInteger, UIImagePickerControllerCameraCaptureMode) {
    UIImagePickerControllerCameraCaptureModePhoto,//拍照模式
    UIImagePickerControllerCameraCaptureModeVideo//視頻錄制模式
};
@property (nonatomic) UIImagePickerControllerCameraDevice cameraDevice;/* 攝像頭設(shè)備 */
typedef NS_ENUM(NSInteger, UIImagePickerControllerCameraDevice) {
    UIImagePickerControllerCameraDeviceRear,//前置攝像頭
    UIImagePickerControllerCameraDeviceFront//后置攝像頭
};
@property (nonatomic) UIImagePickerControllerCameraFlashMode cameraFlashMode;/* 閃光燈模式 */
typedef NS_ENUM(NSInteger, UIImagePickerControllerCameraFlashMode) {
    UIImagePickerControllerCameraFlashModeOff  = -1,//關(guān)閉閃光燈
    UIImagePickerControllerCameraFlashModeAuto = 0,//閃光燈自動豆巨,默認(rèn)
    UIImagePickerControllerCameraFlashModeOn   = 1//打開閃光燈
};

/** 對象方法 */
- (void)takePicture; //拍照                     
- (BOOL)startVideoCapture;//開始錄制視頻
- (void)stopVideoCapture;//停止錄制視頻

/** 代理方法 */
- (void)imagePickerController:(UIImagePickerController *)picker 
didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info;
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker;

/** 相冊操作擴(kuò)展 */

/* 保存圖片到相簿 */
void UIImageWriteToSavedPhotosAlbum(
    UIImage *image,//保存的圖片UIImage
    id completionTarget,//回調(diào)的執(zhí)行者
    SEL completionSelector, //回調(diào)方法
    void *contextInfo//回調(diào)參數(shù)信息
);
//上面一般保存圖片的回調(diào)方法為:
- (void)image:(UIImage *)image 
        didFinishSavingWithError:(NSError *)error 
        contextInfo:(void *)contextInfo;

/* 判斷是否能保存視頻到相簿 */
BOOL UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(NSString *videoPath);
/* 保存視頻到相簿 */
void UISaveVideoAtPathToSavedPhotosAlbum(
    NSString *videoPath, //保存的視頻文件路徑
    id completionTarget, //回調(diào)的執(zhí)行者
    SEL completionSelector,//回調(diào)方法
    void *contextInfo//回調(diào)參數(shù)信息
);
//上面一般保存視頻的回調(diào)方法為:
- (void)video:(NSString *)videoPath 
        didFinishSavingWithError:(NSError *)error 
        contextInfo:(void *)contextInfo;

具體使用

#import "ViewController.h"
#import <MobileCoreServices/MobileCoreServices.h>

@interface ViewController () <UIImagePickerControllerDelegate,UINavigationControllerDelegate>
@property (strong, nonatomic) UIImagePickerController *pickerController;//拾取控制器
@property (strong, nonatomic) IBOutlet UIImageView *showImageView;//顯示圖片
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    //初始化拾取控制器
    [self initPickerController];
}
/* 初始化拾取控制器 */
- (void)initPickerController{
    //創(chuàng)建拾取控制器
    UIImagePickerController *pickerController = [[UIImagePickerController alloc] init];
    //設(shè)置拾取源為攝像頭
    pickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
    //設(shè)置攝像頭為后置
    pickerController.cameraDevice = UIImagePickerControllerCameraDeviceRear;
    pickerController.editing = YES;//設(shè)置運(yùn)行編輯,即可以點(diǎn)擊一些拾取控制器的控件
    pickerController.delegate = self;//設(shè)置代理
    self.pickerController = pickerController;
}
#pragma mark - UI點(diǎn)擊
/* 點(diǎn)擊拍照 */
- (IBAction)imagePicker:(id)sender {
    //設(shè)定拍照的媒體類型
    self.pickerController.mediaTypes = @[(NSString *)kUTTypeImage];
    //設(shè)置攝像頭捕捉模式為捕捉圖片
    self.pickerController.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
    //模式彈出拾取控制器
    [self presentViewController:self.pickerController animated:YES completion:nil];
}
/* 點(diǎn)擊錄像 */
- (IBAction)videoPicker:(id)sender {
    //設(shè)定錄像的媒體類型
    self.pickerController.mediaTypes = @[(NSString *)kUTTypeMovie];
    //設(shè)置攝像頭捕捉模式為捕捉視頻
    self.pickerController.cameraCaptureMode = UIImagePickerControllerCameraCaptureModeVideo;
    //設(shè)置視頻質(zhì)量為高清
    self.pickerController.videoQuality = UIImagePickerControllerQualityTypeHigh;
    //模式彈出拾取控制器
    [self presentViewController:self.pickerController animated:YES completion:nil];
}

#pragma mark - 代理方法
/* 拍照或錄像成功掐场,都會調(diào)用 */
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
{
    //從info取出此時攝像頭的媒體類型
    NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];

    if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {//如果是拍照
        //獲取拍照的圖像
        UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
        //保存圖像到相簿
        UIImageWriteToSavedPhotosAlbum(image, self, 
                  @selector(image:didFinishSavingWithError:contextInfo:), nil);

    } else if ([mediaType isEqualToString:(NSString *)kUTTypeMovie]) {//如果是錄像
        //獲取錄像文件路徑URL
        NSURL *url = [info objectForKey:UIImagePickerControllerMediaURL];
        NSString *path = url.path;
        //判斷能不能保存到相簿
        if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(path)) {
            //保存視頻到相簿
            UISaveVideoAtPathToSavedPhotosAlbum(path, self, 
                   @selector(video:didFinishSavingWithError:contextInfo:), nil);
        }

    }
    //拾取控制器彈回
    [self dismissViewControllerAnimated:YES completion:nil];
}
/* 取消拍照或錄像會調(diào)用 */
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
    NSLog(@"取消");
    //拾取控制器彈回
    [self dismissViewControllerAnimated:YES completion:nil];
}

#pragma mark - 保存圖片或視頻完成的回調(diào)
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error
                                            contextInfo:(void *)contextInfo {
    NSLog(@"保存圖片完成");
    self.showImageView.image = image;
    self.showImageView.contentMode = UIViewContentModeScaleToFill;
}

- (void)video:(NSString *)videoPath didFinishSavingWithError:(NSError *)error
                                                 contextInfo:(void *)contextInfo {
    NSLog(@"保存視頻完成");
}
@end
* AVFoundation 拍照
Camera.jpg

CameraVC.h

//  Created by Rain Dou on 15/10/1.
//  Copyright ? 2015年 shiwo@ShangHai. All rights reserved.

#import <UIKit/UIKit.h>

@interface CameraVC : UIViewController

@property (nonatomic, copy) void(^CameraBlock)(NSURL *fileURL);

@end

CameraVC.m

//  Created by Rain Dou on 15/10/1.
//  Copyright ? 2015年 shiwo@ShangHai. All rights reserved.

#import "CameraVC.h"
#import <AssetsLibrary/AssetsLibrary.h>
#import <AVFoundation/AVFoundation.h>
#import <MobileCoreServices/MobileCoreServices.h>
#import <ImageIO/ImageIO.h>
#import "HollowView.h"

#define SOUNDID   1108
#define TextColor SWColor(255, 204, 26, 1.0)
#define ResetText NSLocalizedString(@"Retake", nil)
#define UseText   NSLocalizedString(@"使用gif", nil)
#define AutoText  NSLocalizedString(@"Auto", nil)
#define OffText   NSLocalizedString(@"Off", nil)
#define OnText    NSLocalizedString(@"On", nil)

/** 視頻文件輸出代理 */
typedef void(^PropertyChangeBlock)(AVCaptureDevice *captureDevice);

@interface CameraVC ()

// AVFoundation
@property (nonatomic, strong) AVCaptureSession *captureSession;
@property (nonatomic, strong) AVCaptureDeviceInput *captureDeviceInput;
@property (nonatomic, strong) AVCaptureStillImageOutput *captureStillImageOutput;
@property (nonatomic, strong) AVCaptureMovieFileOutput *captureMovieFileOutput;
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *captureVideoPreviewLayer;

// view
@property (nonatomic, strong) UIButton *backBtn;
@property (nonatomic, strong) UIButton *toggleBtn;
@property (nonatomic, strong) UIView   *viewContainer;
@property (nonatomic, strong) UIView   *holeView;
@property (nonatomic, strong) UIButton *flashBtn;
@property (nonatomic, strong) UIView   *flashView;
@property (nonatomic, strong) UIButton *takeBtn;
@property (nonatomic, strong) UIButton *resetBtn;
@property (nonatomic, strong) UIButton *useBtn;
@property (nonatomic, strong) UIImageView *focusCursor;

// Data
@property (nonatomic, strong) NSMutableArray *imgArray;
@property (nonatomic, strong) NSURL *gifURL;

@end

@implementation CameraVC

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor blackColor];
    _imgArray = [NSMutableArray array];
    [self setupNavBar];
    [self setContainerView];
    [self setupToolBar];
    [self initAVCaptureSession];
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    self.navigationController.navigationBarHidden = YES;
}
- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    self.navigationController.navigationBarHidden = NO;
}
#pragma mark - init view
- (void)setupNavBar
{
    _backBtn   = [self btnFrame:CGRectMake(12, 12, 40, 40)               title:nil img:@"Back"          superView:self.view action:@selector(backBtnClick)];
    _toggleBtn = [self btnFrame:CGRectMake(SWScreenW/2.0-20, 14, 40, 40) title:nil img:@"CameraToggle"  superView:self.view action:@selector(toggleBtnClick:)];
    _flashBtn  = [self btnFrame:CGRectMake(SWScreenW-52, 12, 40, 40)     title:nil img:@"CameraFlashOn" superView:self.view action:@selector(flashClick:)];
    _flashView = [[UIView alloc] initWithFrame:CGRectMake(0, 12, SWScreenW-52, 40)];
    [self.view addSubview:_flashView];
    CGFloat tmpWidth = (SWScreenW-104)/3.0;
    [self btnFrame:CGRectMake(52+0*tmpWidth, 0, tmpWidth, 40) title:OffText  img:nil superView:_flashView action:@selector(flashOffClick:)];
    [self btnFrame:CGRectMake(52+1*tmpWidth, 0, tmpWidth, 40) title:OnText   img:nil superView:_flashView action:@selector(flashOnClick:)];
    [self btnFrame:CGRectMake(52+2*tmpWidth, 0, tmpWidth, 40) title:AutoText img:nil superView:_flashView action:@selector(flashAutoClick:)];
    _flashView.backgroundColor = [UIColor blackColor];
    _flashView.hidden = YES;
}
- (void)setContainerView
{
    _viewContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 64, SWScreenW, SWScreenH - 174)];
    [self.view addSubview:_viewContainer];

    _holeView = [[HollowView alloc] initWithFrame:_viewContainer.frame];
    [self.view insertSubview:_holeView aboveSubview:_viewContainer];
}
- (void)setupToolBar
{
    _takeBtn = [self btnFrame:CGRectMake(SWScreenW/2.0-30, SWScreenH-110, 60, 110) title:nil img:@"CameraTake" superView:self.view action:@selector(takeBtnClick:)];
    _resetBtn = [self btnFrame:CGRectMake(26, SWScreenH-45, 50, 25) title:ResetText img:nil superView:self.view action:@selector(resetBtnClick:)];
    _resetBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
    _useBtn = [self btnFrame:CGRectMake(SWScreenW-86, SWScreenH-45, 60, 25) title:UseText img:nil superView:self.view action:@selector(useBtnClick:)];
    _resetBtn.hidden = YES;
    _useBtn.hidden = YES;
}
#pragma mark 創(chuàng)建按鈕
- (UIButton *)btnFrame:(CGRect)frame title:(NSString *)title img:(NSString *)img superView:(UIView *)superView action:(SEL)action
{
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.frame = frame;
    if (img) [button setImage:[UIImage imageNamed:img] forState:UIControlStateNormal];
    if (title)
    {
        [button setTitle:title forState:UIControlStateNormal];
        [button setTitleColor:TextColor forState:UIControlStateNormal];
        button.titleLabel.font = Font16;
    }
    [button addTarget:self action:action forControlEvents:UIControlEventTouchUpInside];
    [superView addSubview:button];
    return button;
}
#pragma mark - private method
- (void)initAVCaptureSession
{
    _captureSession = [[AVCaptureSession alloc] init];
    if ([_captureSession canSetSessionPreset:AVCaptureSessionPresetHigh])
    {
        [_captureSession setSessionPreset:AVCaptureSessionPreset640x480];
    }
    
    AVCaptureDevice *captureDevice = [self getCameraDeviceWithPosition:AVCaptureDevicePositionBack];
    if (!captureDevice) {
        NSLog(@"取得后置攝像頭時出現(xiàn)問題.");
        return;
    }
    
    NSError *error = nil;
    _captureDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:captureDevice error:&error];
    if (error) {
        NSLog(@"取得設(shè)備輸入對象時出錯往扔,錯誤原因:%@",error.localizedDescription);
        return;
    }
    
    _captureStillImageOutput = [[AVCaptureStillImageOutput alloc] init];
    NSDictionary *outputSetting = @{AVVideoCodecKey : AVVideoCodecJPEG};
    [_captureStillImageOutput setOutputSettings:outputSetting];
    
    if ([_captureSession canAddInput:_captureDeviceInput])
    {
        [_captureSession addInput:_captureDeviceInput];
    }
    if ([_captureSession canAddOutput:_captureStillImageOutput])
    {
        [_captureSession addOutput:_captureStillImageOutput];
    }
    
    _captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
    CALayer *containerLayer = self.viewContainer.layer;
    containerLayer.masksToBounds = YES;
    _captureVideoPreviewLayer.frame = containerLayer.bounds;
    _captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    [containerLayer insertSublayer:_captureVideoPreviewLayer below:_focusCursor.layer];
    
    [self addNotificationToCaptureDevice:captureDevice];
    [self addGestureRecognizer];
    [self setFlashMode:AVCaptureFlashModeAuto];
    [_captureSession startRunning];
}

- (AVCaptureDevice *)getCameraDeviceWithPosition:(AVCaptureDevicePosition)position
{
    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    for (AVCaptureDevice *camera in devices)
    {
        if ([camera position] == position)
        {
            return camera;
        }
    }
    return nil;
}
#pragma mark 生成gif
- (void)makeGif
{
    NSDictionary *fileProperties = @{(__bridge id)kCGImagePropertyGIFDictionary:@{(__bridge id)kCGImagePropertyGIFLoopCount:@0,}};
    NSDictionary *frameProperties = @{(__bridge id)kCGImagePropertyGIFDictionary:@{(__bridge id)kCGImagePropertyGIFDelayTime:@0.5f,}};
    NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil];
    NSURL *fileURL = [documentsDirectoryURL URLByAppendingPathComponent:@"animated.gif"];
    CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)fileURL, kUTTypeGIF, self.imgArray.count, NULL);
    CGImageDestinationSetProperties(destination, (__bridge CFDictionaryRef)fileProperties);
    
    for (NSUInteger i = 0; i < self.imgArray.count; i++)
    {
        @autoreleasepool
        {
            CGImageDestinationAddImage(destination, ((UIImage *)self.imgArray[i]).CGImage, (__bridge CFDictionaryRef)frameProperties);
        }
    }
    
    if (!CGImageDestinationFinalize(destination))
    {
        NSLog(@"failed to finalize image destination");
    }
    CFRelease(destination);
    self.gifURL = fileURL;
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"animated.gif"];
    SWInfoLog(@"");
    SWLog(@"%@",NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES));
    // 保存到本地相冊
    NSData *data = [NSData dataWithContentsOfFile:path];
    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
    [library writeImageDataToSavedPhotosAlbum:data metadata:nil completionBlock:^(NSURL *assetURL, NSError *error) {
        SWInfoLog(@"");
        NSLog(@"Success at %@", [assetURL path] );
    }];
![Camera.jpg](http://upload-images.jianshu.io/upload_images/1465510-f8d27817f1ffd72c.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

}
#pragma mark - Notification
#pragma mark 給輸入設(shè)備添加通知
- (void)addNotificationToCaptureDevice:(AVCaptureDevice *)captureDevice
{
    // 添加區(qū)域改變捕獲通知首先設(shè)置設(shè)備允許捕獲
    [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {
        captureDevice.subjectAreaChangeMonitoringEnabled = YES;
    }];
    [SWNotification addObserver:self selector:@selector(areaChange:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:captureDevice];
}
#pragma mark 給會話添加通知
- (void)addNotificationToCaptureSession:(AVCaptureSession *)captureSession
{
    [SWNotification addObserver:self selector:@selector(sessionRuntimeError:) name:AVCaptureSessionRuntimeErrorNotification object:captureSession];
}
#pragma mark 移除設(shè)備通知
- (void)removeNotificationFromCaptureDevice:(AVCaptureDevice *)captureDevice
{
    [SWNotification removeObserver:self name:AVCaptureDeviceSubjectAreaDidChangeNotification object:captureDevice];
}
- (void)changeDeviceProperty:(PropertyChangeBlock)propertyChange
{
    AVCaptureDevice *captureDevice = [_captureDeviceInput device];
    NSError *error = nil;
    // 注意改變設(shè)備屬性前先加鎖,調(diào)用完解鎖
    if ([captureDevice lockForConfiguration:&error])
    {
        propertyChange(captureDevice);
        [captureDevice unlockForConfiguration];
    }
    else SWLog(@"changeDevicePropertyError:%@",error.localizedDescription);
}

#pragma mark 添加手勢
- (void)addGestureRecognizer
{
    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapScreen:)];
    [_viewContainer addGestureRecognizer:tapGesture];
}
#pragma mark 點(diǎn)擊屏幕聚焦
- (void)tapScreen:(UITapGestureRecognizer *)gesture
{
    CGPoint point= [gesture locationInView:self.viewContainer];
    // 將UI坐標(biāo)轉(zhuǎn)化為攝像頭坐標(biāo)
    CGPoint cameraPoint= [self.captureVideoPreviewLayer captureDevicePointOfInterestForPoint:point];
    [self setFocusCursorWithPoint:point];
    [self focusWithMode:AVCaptureFocusModeAutoFocus exposureMode:AVCaptureExposureModeAutoExpose atPoint:cameraPoint];
}
#pragma mark 聚焦框
- (void)setFocusCursorWithPoint:(CGPoint)point
{
    _focusCursor.transform = CGAffineTransformMakeScale(1.5, 1.5);
    _focusCursor.alpha = 1.0;
    [UIView animateWithDuration:1.0 animations:^{
        self.focusCursor.transform = CGAffineTransformIdentity;
    } completion:^(BOOL finished) {
        self.focusCursor.alpha = 0;
        
    }];
}
#pragma mark 設(shè)置聚焦點(diǎn)
- (void)focusWithMode:(AVCaptureFocusMode)focusMode exposureMode:(AVCaptureExposureMode)exposureMode atPoint:(CGPoint)point
{
    [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {
        if ([captureDevice isFocusModeSupported:focusMode])
        {
            [captureDevice setFocusMode:AVCaptureFocusModeAutoFocus];
        }
        if ([captureDevice isFocusPointOfInterestSupported])
        {
            [captureDevice setFocusPointOfInterest:point];
        }
        if ([captureDevice isExposureModeSupported:exposureMode])
        {
            [captureDevice setExposureMode:AVCaptureExposureModeAutoExpose];
        }
        if ([captureDevice isExposurePointOfInterestSupported])
        {
            [captureDevice setExposurePointOfInterest:point];
        }
    }];
}

#pragma mark 設(shè)置聚焦模式
- (void)setFocusMode:(AVCaptureFocusMode)focusMode
{
    [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {
        if ([captureDevice isFocusModeSupported:focusMode])
        {
            [captureDevice setFocusMode:focusMode];
        }
    }];
}
#pragma mark 設(shè)置曝光模式
- (void)setExposureMode:(AVCaptureExposureMode)exposureMode
{
    [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {
        if ([captureDevice isExposureModeSupported:exposureMode])
        {
            [captureDevice setExposureMode:exposureMode];
        }
    }];
}
#pragma mark 設(shè)置閃光燈模式
- (void)setFlashMode:(AVCaptureFlashMode)flashMode
{
    switch (flashMode) {
        case AVCaptureFlashModeOff:
            [_flashBtn setImage:[UIImage imageNamed:@"CameraFlashOff"] forState:UIControlStateNormal];
            break;
        case AVCaptureFlashModeOn:
            [_flashBtn setImage:[UIImage imageNamed:@"CameraFlashOn"] forState:UIControlStateNormal];
            break;
        case AVCaptureFlashModeAuto:
            [_flashBtn setImage:[UIImage imageNamed:@"CameraFlashAuto"] forState:UIControlStateNormal];
            break;
        default:
            break;
    }
    [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {
        if ([captureDevice isFlashModeSupported:flashMode])
        {
            [captureDevice setFlashMode:flashMode];
        }
    }];
}
#pragma mark - 事件響應(yīng)
#pragma mark 返回
- (void)backBtnClick
{
    CATransition* transition = [CATransition animation];
    transition.type = kCATransitionReveal;
    transition.subtype = kCATransitionFromBottom;
    [self.navigationController.view.layer addAnimation:transition forKey:kCATransition];
    [self.navigationController popViewControllerAnimated:NO];
}
#pragma mark 切換攝像頭
- (void)toggleBtnClick:(UIButton *)sender
{
    AVCaptureDevice *currentDevice = [_captureDeviceInput device];
    AVCaptureDevicePosition currentPosition = [currentDevice position];
    [self removeNotificationFromCaptureDevice:currentDevice];
    AVCaptureDevice *toChangeDevice;
    AVCaptureDevicePosition toChangePosition = AVCaptureDevicePositionFront;
    if (currentPosition == AVCaptureDevicePositionUnspecified || currentPosition == AVCaptureDevicePositionFront)
    {
        toChangePosition = AVCaptureDevicePositionBack;
    }
    toChangeDevice = [self getCameraDeviceWithPosition:toChangePosition];
    [self addNotificationToCaptureDevice:toChangeDevice];
    // 獲得要調(diào)整的設(shè)備輸入對象
    AVCaptureDeviceInput *toChangeDeviceInput = [[AVCaptureDeviceInput alloc]initWithDevice:toChangeDevice error:nil];
    
    // 改變會話的配置前一定要先開啟配置贩猎,配置完成后提交配置改變
    [self.captureSession beginConfiguration];
    // 移除原有輸入對象
    [self.captureSession removeInput:self.captureDeviceInput];
    // 添加新的輸入對象
    if ([self.captureSession canAddInput:toChangeDeviceInput])
    {
        [self.captureSession addInput:toChangeDeviceInput];
        self.captureDeviceInput = toChangeDeviceInput;
    }
    // 提交會話配置
    [self.captureSession commitConfiguration];
    [self setFlashMode:AVCaptureFlashModeAuto];

}
#pragma mark 自動閃光燈開啟
- (void)flashClick:(UIButton *)sender
{
    _flashView.hidden = NO;
}
- (void)flashAutoClick:(UIButton *)sender
{
    [self setFlashMode:AVCaptureFlashModeAuto];
    _flashView.hidden = YES;
}
#pragma mark 打開閃光燈
- (void)flashOnClick:(UIButton *)sender
{
    [self setFlashMode:AVCaptureFlashModeOn];
    _flashView.hidden = YES;
}
#pragma mark 關(guān)閉閃光燈
- (void)flashOffClick:(UIButton *)sender
{
    [self setFlashMode:AVCaptureFlashModeOff];
    _flashView.hidden = YES;
}

#pragma mark 拍照
- (void)takeBtnClick:(UIButton *)sender
{
    [[self class] cancelPreviousPerformRequestsWithTarget:self selector:@selector(takePhotos) object:sender];
    [self performSelector:@selector(takePhotos) withObject:sender afterDelay:0.2f];
}
- (void)takePhotos
{
    AudioServicesPlaySystemSound(SOUNDID);
    // 根據(jù)設(shè)備輸出獲得連接
    AVCaptureConnection *captureConnection = [_captureStillImageOutput connectionWithMediaType:AVMediaTypeVideo];
    // 根據(jù)連接取得設(shè)備輸出的數(shù)據(jù)
    [_captureStillImageOutput captureStillImageAsynchronouslyFromConnection:captureConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error)
     {
         if (imageDataSampleBuffer)
         {
             NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
             UIImage *image = [UIImage imageWithData:imageData];
             UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
             UIImage *lastImg = [UIImage squareImage:image scaledToSize:SWScreenW];
             [_imgArray addObject:lastImg];
             if (_imgArray.count >=5)
             {
                 [self takePhotoFinished];
             }
         }
     }];
}
#pragma mark 完成拍攝條件
- (void)takePhotoFinished
{
    _backBtn.hidden = YES;
    _toggleBtn.hidden = YES;
    _takeBtn.hidden = YES;
    _resetBtn.hidden = NO;
    _useBtn.hidden = NO;
    [self makeGif];
}
#pragma mark 重新拍攝
- (void)resetBtnClick:(UIButton *)sender
{
    if (_imgArray)
    {
        [_imgArray removeAllObjects];
    }
    _backBtn.hidden = NO;
    _toggleBtn.hidden = NO;
    _takeBtn.hidden = NO;
    _resetBtn.hidden = YES;
    _useBtn.hidden = YES;
    _flashView.hidden = YES;
    [self setFlashMode:AVCaptureFlashModeAuto];
}
#pragma mark 使用gif
- (void)useBtnClick:(UIButton *)sender
{
    if(self.CameraBlock)
    {
        self.CameraBlock(self.gifURL);
    }
    [self backBtnClick];
}

#pragma mark - 通知對象
- (void)areaChange:(NSNotification *)notification
{
    SWLog(@"捕獲區(qū)域改變");
}
- (void)sessionRuntimeError:(NSNotification *)notification
{
    SWLog(@"會話發(fā)生錯誤");
}
- (void)dealloc {
    [_captureSession stopRunning];
    [SWNotification removeObserver:self];
}
- (BOOL)prefersStatusBarHidden {
    return YES;
}
@end

附加

解決拍照后圖片旋轉(zhuǎn)甚至顛倒bug

// [self fixOrientation:image]
- (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:
            // Grr...
            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;
}
* 附

iOS調(diào)用相機(jī)和相冊-細(xì)節(jié)化
封裝相機(jī)功能->>>>>block返回image
仿微信小視頻拍照播放
swift視頻錄制
iOS視頻壓縮存儲至本地并上傳至服務(wù)器
swift avf拍照,錄制
RSKImageCropViewController與TZImagePickerController

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瓤球,一起剝皮案震驚了整個濱河市融欧,隨后出現(xiàn)的幾起案子敏弃,更是在濱河造成了極大的恐慌卦羡,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件麦到,死亡現(xiàn)場離奇詭異绿饵,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)瓶颠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進(jìn)店門拟赊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人粹淋,你說我怎么就攤上這事吸祟。” “怎么了桃移?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵屋匕,是天一觀的道長。 經(jīng)常有香客問我借杰,道長过吻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任蔗衡,我火速辦了婚禮纤虽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绞惦。我一直安慰自己逼纸,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布济蝉。 她就那樣靜靜地躺著杰刽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪堆生。 梳的紋絲不亂的頭發(fā)上专缠,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天,我揣著相機(jī)與錄音淑仆,去河邊找鬼涝婉。 笑死,一個胖子當(dāng)著我的面吹牛蔗怠,可吹牛的內(nèi)容都是我干的墩弯。 我是一名探鬼主播吩跋,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼渔工!你這毒婦竟也來了锌钮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤引矩,失蹤者是張志新(化名)和其女友劉穎梁丘,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體旺韭,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡氛谜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了区端。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片值漫。...
    茶點(diǎn)故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖织盼,靈堂內(nèi)的尸體忽然破棺而出杨何,到底是詐尸還是另有隱情,我是刑警寧澤沥邻,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布危虱,位于F島的核電站,受9級特大地震影響谋国,放射性物質(zhì)發(fā)生泄漏槽地。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一芦瘾、第九天 我趴在偏房一處隱蔽的房頂上張望捌蚊。 院中可真熱鬧,春花似錦近弟、人聲如沸缅糟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽窗宦。三九已至,卻和暖如春二鳄,著一層夾襖步出監(jiān)牢的瞬間赴涵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工订讼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留髓窜,地道東北人。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像寄纵,于是被迫代替她去往敵國和親鳖敷。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評論 2 355

推薦閱讀更多精彩內(nèi)容