iOS自定义相机功能

2022-07-20 16:12:59

大多数app都会涉及到上传照片这个功能,图片来源无非是从相册获取或者相机拍摄。如果不是特别要求,调用系统已经满足需求。但对于特殊需求,就需要自定义相机拍摄界面了。对于无需定制的相机,使用系统的UIKi...

大多数app都会涉及到上传照片这个功能,图片来源无非是从相册获取或者相机拍摄。如果不是特别要求,调用系统已经满足需求。但对于特殊需求,就需要自定义相机拍摄界面了。

对于无需定制的相机,使用系统的UIKit库里的UIImagePickerController类,几行代码,几个代理方法就可满足所需。但如果要深度定制,就要系统库AVFoundation内部的相关类。

创建自己的相机管理类CameraManager(继承于NSObject)

.h文件

#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
//拍照后的回调,传递拍摄的照片
typedef void(^DidCapturePhotoblock)(UIImage *stillImage);

@interface PXCameraManager : NSObject

@property (nonatomic, strong) AVCaptureSession *session;//AVCaptureSession对象来执行输入设备和输出设备之间的数据传递

@property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer;//预览图层,来显示照相机拍摄到的画面

@property (nonatomic, strong) AVCaptureDeviceInput *deviceInput;//AVCaptureDeviceInput对象是输入流

@property (nonatomic, strong) AVCaptureStillImageOutput *stillImageOutput;//照片输出流对象

@property (nonatomic, assign) CGRect previewLayerFrame;//拍照区域

/* 为其他类提供的自定义接口 */

//设置拍照区域 (其中targetView为要展示拍照界面的view)
- (void)configureWithtargetViewLayer:(UIView *)targetView previewRect:(CGRect)preivewRect;

//拍照成功回调
- (void)takePicture:(DidCapturePhotoBlock)block;

//添加/移除相机浮层(如果有需求要在相机拍照区域添加浮层的时候使用)
- (void)addCoverImageWithImage:(UIImage *)image;
- (void)removeCoverImageWithImage:(UIImage *)image;

//前后摄像头切换
- (void)switchCameras;

//闪光灯切换
- (void)configCameraFlashlight;


@end

.m文件

@property (nonatomic, strong) UIView *preview;//展现拍照区编程域的view
@property (nonatomic, strong) UIImageView *coverImageView;//拍照区域浮层

@property (nonatomic, assign) BOOL isCaremaBack;
@property (nonatomic, assign) AVCaptureFlashMode flashMode;

//初始化的时候设置自己想要的默编程认属性
- (instancetype)init{

  self = [super init];
  if (self) {

    self.isCaremaBack = YES;//默认后置摄像头
    self.flashMode = AVCaptureFlashModeAuto;//默认自动闪光灯
  }
  return self;
}

实现接口的方法

1、准备相关硬件

- (void)configureWithTargetViewLayer:(UIView *)targetView previewRect:(CGRect)preivewRect{

  self.preview = targetView;

  //开始一些相机相关硬件配置  
  [self addSession];//创建session

  [self addVideoPreviewLayerWithRect:preivewRect];//用session 创建 创建layer

  [self addvideoInputBackCamera:self.isCaremaBack];//给session 配置摄像头

  [self addVideoFlashlightWithFlashModel:self.flashMode];//配置闪光灯

  [self addStillImageOutput];//给session 配置输出
}

2、拍照

#pragma mark -
- (void)takePicture:(DidCapturePhotoBlock)block{

  AVCaptureConnection *captureConnection = [self findCaptureConnection];

  [captureConnection setVideoScaleAndCropFactor:1.0f];

  [_stillImageOutput captureStillImageAsynchronouslyFromConnection:captureConnection completionHandler:^(cmsampleBufferRef imageDataSampleBuffer, NSError *error) {

    NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];

    UIImage *image = [UIImage imageWithData:imageData];
    //这里可以根据不同需求对拍摄到的照片做一些压缩或者裁剪的处理,这里我就偷懒不弄了。
    if (block) {
      block(image);
    }
  }];

}

3、切换摄像头

- (void)switchCameras{
  if (!_deviceInput) {
    return;
  }
  [_session beginConfiguration];

  [_session removeInput:_deviceInput];
  self.isCaremaBack = !self.isCaremaBack;
  [self addvideoInputBackCamera:self.isCaremaBack];

  [_session commitConfiguration];
}

4、切换闪光灯

- (void)configCameraFlashlight{

  switch (self.flashMode) {
    case AVCaptureFlashModeAuto:
    {
      self.flashMode = AVCaptureFlashModeOff;
    }
      break;
    case AVCaptureFlashModeOff:
    {
      self.flashMode = AVCaptureFlashModeOn;
    }
      break;
    case AVCaptureFlashModeOn:
    {
      self.flashMode = AVCaptureFlashModeAuto;
    }
      break;
    default:
      break;
  }

  [self addVideoFlashlightWithFlashModel:self.flashMode];

}

添加/移除 浮层

- (void)addCoverImageWithImage:(UIImage *)image{

  _coverImageView.image = image;
}
- (void)removeCoverImageWithImage:(UIImage *)image{

  _coverImageView.image = nil;

}

下面是配置硬件里的几个方法实现

- (void)addSession{

  if (!self.session) {
    AVCaptureSession *session = [[AVCaptureSession alloc]init];
    self.session = session;
  }
}
- (void)addVideoPreviewLayerWithRect:(CGRect)previewRect{

  if (!self.previewLayer) {
    AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:_session];
    previewLayer.videoGravity = AVLayerVideoGravityResizeASPectFill;

    self.previewLayer = previewLayer;

    [self.preview.layer addSublayer:self.previewLayer];

  }

  self.previewLayer.frame = previewRect;
}
- (void)addvideoInputBackCamera:(BOOL)back{

  NSArray *devices = [AVCaptureDevice devices];

  AVCaptureDevice *frontCamera;
  AVCaptureDevice *backCamera;
  //获取 前、后 摄像头
  for (AVCaptureDevice *device inhttp://www.cppcns.com devices) {

    if ([device hasMediaType:AVMediaTypeVideo]) {

      if ([device position] == AVCaptureDevicePositionBack) {

        backCamera = device;

      }else if([djavascriptevice position] == AVCaptureDevicePositionFront){

        frontCamera = device;

      }
    }
  }

  NSError *error = nil;


  if(back){
    AVCaptureDeviceInput *backCameraDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:backCamera error:&error];
    if (!error) {

      if ([_session canAddInput:backCameraDeviceInput]) {

        [_session addInput:backCameraDeviceInput];
        self.deviceInput = backCameraDeviceInput;

      }else{
        NSLog(@"出错啦");
      }
    }

  }else{

    AVCaptureDeviceInput *frontCameraDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:frontCamera error:&error];
    if (!error) {

      if ([_session canAddInput:frontCameraDeviceInput]) {

        [_session addInput:frontCameraDeviceInput];
        self.deviceInput = frontCameraDeviceInput;

      }else{
        NSLog(@"出错啦");
      }
    }
  }


}
- (void)addVideoFlashlightWithFlashModel:(AVCaptureFlashMode )flashModel{

  AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
  [device lockForConfiguration:nil];

  if ([device hasFlash]) {
    device.flashMode = self.flashMode;
  }

  [device unlockForConfiguration];
}
- (void)addStillImageOutput{

  if (!self.stillImageOutput) {

    AVCaptureStillImageOutput *stillImageOutput = [[AVCaptureStillImageOutput alloc]init];
    NSDictionary *outPutSettingDict = [[NSDictionary alloc]initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey, nil];
    stillImageOutput.outputSettings = outPutSettingDict;

    [_session addOutput:stillImageOutput];

    self.stillImageOutput = stillImageOutput;
  }


}
- (AVCaptureConnectjsion *)findCaptureConnection{


  AVCaptureConnection *videoConnection;

  for (AVCaptureConnection *connection in _stillImageOutput.connections ) {
    for (AVCaptureInputPort *port in connection.inputPorts) {

      if ([[port mediaType] isEqual:AVMediaTypeVideo]) {

        videoConnection = connection;

        return videoConnection;
      }
    }
  }

  return nil;

}

到此,一个自定义相机的类就有了,要使用的时候,尽管调用吧。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。