自定义拍照

关于iOS调用摄像机来获取照片,通常我们都会调用UIImagePickerController来调用系统提供的相机来拍照,这个控件非常好用。但是有时UIImagePickerController控件无法满足我们的需求,例如我们需要更加复杂的OverlayerView,这时候我们就要自己构造一个摄像机控件了。


 0.AVCapture  <AVFoundation/AVFoundation.h>

 媒体采集需要的几个对象:

 1AVCaptureDevice 代表抽象的硬件设备(如前置摄像头,后置摄像头等)

 2AVCaptureInput 代表输入设备(可以是它的子类),它配置抽象硬件设备的ports

 3AVCaptureOutput 它代表输出数据,管理着输出到一个movie或者图像。

 4AVCaptureSession 它是inputoutput的桥梁。它协调着inputoutput的数据传输。


 关系:

 有很多Deviceinput,也有很多数据类型的Output,都通过一个Capture Session来控制进行传输。也即:CaptureDevice适配AVCaptureInput,通过Session来输入到AVCaptureOutput中。这样也就达到了从设备到文件等持久化输入目的(如从相机设备采集图像到UIImage中)。


 那么存在一个问题了:视频输入(input)就对应视频的输出(output),而音频输入就对应音频的输出,因而需要建立对应的Connections,来各自连接它们。而这样的连接对象,是由AVCaptureSession来持有的,这个对象叫AVCaptureConnection

 在一个AVCaptureConnection中,这里维持着对应的数据传输输入到数据输出的过程(detail过程)。这里,AVCaptureInput或其子类对象包含着各种input port,通过各种input port,我们的AVCaptureOutput可以获取相应的数据。


 一个AVCaptureConnection可以控制inputoutput的数据传输。




 1.Session及其使用模式

 You use an instance to coordinate the flow of data from AV input devices to outputs. You add the capture devices and outputs you want to the session, then start data flow by sending the session a startRunning message, and stop recording by sending a stopRunning message.


 AVCaptureSession *session = [AVCaptureSession alloc] init];

 [session startRunning];


 这里表明了,需要create一个session,然后发running消息给它,它会自动跑起来,把输入设备的东西,提交到输出设备中。


 若想在一个已经使用上的session(已经startRunning)做更换新的device、删除旧的device等一系列的操作,那么就需要使用如下方法:

AVCaptureSession *session;

[session beginConfiguration];

// Remove an existing capture device.

// Add a new capture device.

// Reset the preset.

[session commitConfiguration];


 当然,如果session的时候发生了异常,那么我们可以通过notificationobserve相关的事件(可以在AVCaptureSession Class Reference中的Notifications中找到相应的情况),而session如果出现相应问题的时候,它会post出来,此时我们就可以处理了。



 2.AVCaptureDevice,主要用来获取iPhone一些关于相机设备的属性。

 InputDevice即是对硬件的抽象,一对一的。一个AVCaptureDevice对象,对应一个实际的硬件设备。


  那么显然,我们可以通过AVCaptureDevice的类方法devicesdevicesWithMediaType去获取全部或局部设备列表。(当然也可以检测相应的设备是否可以使用,这里注意有设备抢占问题,当前是否可用)


 相机设备可以用下面的方法判断设备是否支持相关属性(property),比如对焦方式或者对焦状态Focus modes

 [currentDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus];


1. 前置和后置摄像头

enum {

    AVCaptureDevicePositionBack = 1,

    AVCaptureDevicePositionFront = 2

};

typedef NSInteger AVCaptureDevicePosition;


2. 闪光灯开关

enum {

    AVCaptureFlashModeOff = 0,

    AVCaptureFlashModeOn = 1,

    AVCaptureFlashModeAuto = 2

};

typedef NSInteger AVCaptureFlashMode;


3. 手电筒开关

enum {

    AVCaptureTorchModelOff = 0,

    AVCaptureTorchModelOn = 1,

    AVCaptureTorchModeAuto = 2

};

typedef NSInteger AVCaptureTorchMode;


4. 焦距调整

enum {

    AVCaptureFocusModelLocked = 0,

    AVCaptureFocusModeAutoFocus = 1,

    AVCaptureFocusModeContinousAutoFocus = 2

};

typedef NSInteger AVCaptureFocusMode;


5. 曝光量调节

enum {

    AVCaptureExposureModeLocked = 0,

    AVCaptureExposureModeAutoExpose = 1,

    AVCaptureExposureModeContinuousAutoExposure = 2

};

typedef NSInteger AVCaptureExposureMode;


6. 白平衡

enum {

    AVCaptureWhiteBalanceModeLocked = 0,

    AVCaptureWhiteBalanceModeAutoWhiteBalance = 1,

    AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance = 2

};

typedef NSInteger AVCaptureWhiteBalanceMode;



 3. CaptureInput的构建和添加到Session中的方法

 创建并配置输入设备

AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

NSError *error = nil;

AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];


// 添加inputsession的模式是(检查可否添加到session,然后根据情况添加或者不添加)

AVCaptureSession *captureSession = <#Get a capture session#>;

if ([captureSession canAddInput:input]) {

    [captureSession addInput:input];

}



4.output的分类和使用

ios中,分为MovieFileVideoDataAudioDataStillImage几种output,使用方式类似,只是范围不同。另外,它们都继承于AVCaptureOutput


第一个是输出成movie文件,第二个适用于逐个Frame的处理,第三个适用于声音采集,第四个是still image(静态图像<拍照>)相关。


他们的添加方式都是使用sessionaddOutput方法。


 5.AVCaptureStillImageOutput 照片输出流对象


 6. AVCaptureVideoPreviewLayer 预览图层,来显示照相机拍摄到的画面




完整代码如下:


#import "ViewController.h"

#import <AVFoundation/AVFoundation.h>



@interface ViewController ()

{}


//AVCaptureSession对象来执行输入设备和输出设备之间的数据传输

@property (nonatomic,strong) AVCaptureSession *session;

//AVCaptureDeviceInput对象是输入流

@property (nonatomic,strong) AVCaptureDeviceInput *videoInput;

//照片输出流对象

@property (nonatomic,strong) AVCaptureStillImageOutput *stillImageOutput;

//预览图层、来显示照相机拍摄到的画面

@property (nonatomic,strong) AVCaptureVideoPreviewLayer *previewlayer;

//切换前后镜头的按钮

@property (nonatomic,strong) UIButton *changeButton;

//拍照按钮

@property (nonatomic,strong) UIButton *cameraButton;

//放置预览图的view

@property (nonatomic,strong) UIView *cameraShowView;

//用来展示拍照获取的图片

@property (nonatomic,strong) UIImageView *imageShowView;



@end


@implementation ViewController




- (void)viewDidLoad {

    [super viewDidLoad];

    [self initCameraShowView];

    [self initImageShowView];

    [self initButton];

 //   [self setUpCameraLayer];

    [self initialSession];

     [self setUpCameraLayer];

    // Do any additional setup after loading the view, typically from a nib.

}


-(void)setUpCameraLayer

{

    if (_previewlayer == nil) {

        _previewlayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:_session];

        UIView *view = _cameraShowView;

        CALayer *viewlayer = [view layer];

        [viewlayer setMasksToBounds:YES];

    

        [_previewlayer setFrame:view.bounds];

        [_previewlayer setVideoGravity:AVLayerVideoGravityResizeAspect];

        [viewlayer addSublayer:_previewlayer];

    }

}



-(void)initialSession

{

    _session = [[AVCaptureSession alloc]init];

    _videoInput = [[AVCaptureDeviceInput alloc]initWithDevice:[self backCamera] error:nil];

    if (!_videoInput) {

      //  UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"无法使用相机" message:@"请在iPhone\"设置-隐私-相机\"中允许访问相机" preferredStyle:UIAlertControllerStyleAlert];

       // UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleCancel handler:nil];

        //[alert addAction:cancelAction];

      //  [self presentViewController:alert animated:YES completion:nil];

        UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"无法使用相机" message:@"请在iPhone\"设置-隐私-相机\"中允许访问相机" delegate:self cancelButtonTitle:@"确认" otherButtonTitles:nil, nil];

        [alertView show];

    }

    _stillImageOutput = [[AVCaptureStillImageOutput alloc]init];

    //

    NSDictionary *outPutSettings = [[NSDictionary alloc]initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey, nil];

    [_stillImageOutput setOutputSettings:outPutSettings];

    if ([_session canAddInput:_videoInput]) {

        [_session addInput:_videoInput];

    }

    if ([_session canAddOutput:_stillImageOutput]) {

        [_session addOutput:_stillImageOutput];

    }

        [_session startRunning];

    

}


//获取前后摄像头对象

-(AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition)position

{

    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];

    for (AVCaptureDevice *device in devices) {

        if (device.position == position) {

            return device;

        }

    }

    return nil;

}


-(AVCaptureDevice *)frontCanera

{

    return [self cameraWithPosition:AVCaptureDevicePositionFront];

}

-(AVCaptureDevice *)backCamera

{

    return [self cameraWithPosition:AVCaptureDevicePositionBack];

}


-(void)viewDidAppear:(BOOL)animated

{

    [super viewDidAppear:animated];

//    if (self.session) {

//        [self.session startRunning];

//    }

}


-(void)viewDidDisappear:(BOOL)animated

{

    [super viewDidDisappear:animated];

    [_session stopRunning];

}



-(void)initCameraShowView

{

    _cameraShowView = [[UIView alloc]initWithFrame:self.view.frame];

    [self.view addSubview:_cameraShowView];

}



-(void)initImageShowView

{

    _imageShowView = [[UIImageView alloc]initWithFrame:CGRectMake(0, self.view.frame.size.height-200*self.view.bounds.size.height/self.view.bounds.size.width, 200, 200*self.view.bounds.size.height/self.view.bounds.size.width)];

    NSLog(@"%f",200*self.view.bounds.size.height/self.view.bounds.size.width);

    _imageShowView.contentMode = UIViewContentModeScaleToFill;

    _imageShowView.backgroundColor = [UIColor whiteColor];

    [self.view addSubview:_imageShowView];

}


-(void)initButton

{

    //UIButton *cameraButton = [[UIButton alloc]init];

    //_cameraButton = cameraButton;

    _cameraButton = [UIButton buttonWithType:UIButtonTypeSystem];

    _cameraButton.frame = CGRectMake(10, 30, 60, 30);

    _cameraButton.backgroundColor = [UIColor greenColor];

    [_cameraButton setTitle:@"拍照" forState:UIControlStateNormal];

    [_cameraButton addTarget:self action:@selector(cameraButtonActon) forControlEvents:UIControlEventTouchUpInside];

    [self.view addSubview:_cameraButton];

    

    

    _changeButton = [UIButton buttonWithType:UIButtonTypeSystem];

    _changeButton.frame = CGRectMake(80, 30, 60, 30);

    _changeButton.backgroundColor = [UIColor greenColor];

    [_changeButton setTitle:@"改变镜头" forState:UIControlStateNormal];

    [_changeButton addTarget:self action:@selector(changeButtonActon) forControlEvents:UIControlEventTouchUpInside];

    [self.view addSubview:_changeButton];

}

//拍照按钮

-(void)cameraButtonActon

{

    AVCaptureConnection *videoConnection = [_stillImageOutput connectionWithMediaType:AVMediaTypeVideo];

    if (!videoConnection) {

        return;

    }

    [_stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {

        if (imageDataSampleBuffer == nil) {

            return ;

        }

        NSData *imagedata  = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];

        UIImage *image = [UIImage imageWithData:imagedata];

        NSLog(@"image size  = %@",NSStringFromCGSize(image.size));

        _imageShowView.image = image;

    }];

}

// 切换镜头

-(void)changeButtonActon

{

    NSUInteger cameraCount = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo] count];

    if (cameraCount>1) {

        NSError *error;

        AVCaptureDeviceInput *newVideoInput;

        AVCaptureDevicePosition positon = [[_videoInput device]position];

        

        if (positon == AVCaptureDevicePositionBack) {

            newVideoInput = [[AVCaptureDeviceInput alloc]initWithDevice:[self frontCanera] error:&error];

        }else if (positon == AVCaptureDevicePositionFront)

        {

            newVideoInput = [[AVCaptureDeviceInput alloc]initWithDevice:[self backCamera] error:&error];

        }else

        {

            return;

        }

        if (newVideoInput != nil) {

            [_session beginConfiguration];

            [_session removeInput:_videoInput];

            if ([_session canAddInput:newVideoInput]) {

                [_session addInput:newVideoInput];

                _videoInput  = newVideoInput;

            }else

            {

                [_session addInput:_videoInput];

            }

            [self.session commitConfiguration];

        }else if (error)

        {

            NSLog(@"change camera failed .error = %@",error);

        }

    }

}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
iOS Objective-C 中自定义相片拍照功能,可以使用系统提供的 UIImagePickerController 类。UIImagePickerController 是一个系统自带的 UIImagePickerController 控制器,它提供了相机和相册的访问功能,可以方便地实现自定义相片拍照功能。 以下是简单的实现步骤: 1. 导入 UIImagePickerController 类: ``` #import <UIKit/UIKit.h> ``` 2. 创建 UIImagePickerController 实例: ``` UIImagePickerController *pickerController = [[UIImagePickerController alloc] init]; ``` 3. 配置 UIImagePickerController 实例: ``` pickerController.sourceType = UIImagePickerControllerSourceTypeCamera; // 设置为相机模式 pickerController.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto; // 设置为拍照模式 pickerController.cameraDevice = UIImagePickerControllerCameraDeviceRear; // 设置为后置摄像头 pickerController.allowsEditing = NO; // 禁止编辑 pickerController.delegate = self; // 设置代理 ``` 4. 打开相机: ``` [self presentViewController:pickerController animated:YES completion:nil]; ``` 5. 处理拍照结果: ``` - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info { UIImage *image = info[UIImagePickerControllerOriginalImage]; // 处理拍照结果 [picker dismissViewControllerAnimated:YES completion:nil]; } ``` 通过系统提供的 UIImagePickerController 控制器,我们可以轻松地实现自定义相片拍照功能。如果需要进一步定制相机界面和功能,可以考虑使用 AVFoundation 框架,自定义相机界面和拍照功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值