iOS隨筆——自定義照相機(jī)

1.工具類(CameraManager)

一個自定義照相機(jī)的工具類你可能需要以下功能:
這個工具類看起來可能是這樣的:

  • 用戶相機(jī)授權(quán)檢測
 + (BOOL)checkAuthority;
  • 通過一個自定義視圖初始化
 - (instancetype)initWithCameraCustomView:(UIView *)customView;
  • 拍照結(jié)束的照片返回可以是代理或者block
 - (void)takePhotoWithImageBlock:(void(^)(UIImage *originImg, NSError *error))imageBlock;
  • 開始/結(jié)束拍照
  - (void)startCamera; 
  - (void)stopCamera;
  • 閃光燈、聚焦、縮放、前后攝像頭切換、照片裁剪加工等等

自定義相機(jī)的實現(xiàn)基于AVFoundation框架

來源蘋果官方,這里只關(guān)注照相功能
來源蘋果官方,這里只關(guān)注照相功能

1.AVCaptureSession

自定義相機(jī)的核心類,主要用于建立輸入流和輸出流之間的聯(lián)系。
你需要實現(xiàn)以下基本方法:

 - (void)addInput:(AVCaptureInput *)input;    // 添加輸入設(shè)備
 - (void)addOutput:(AVCaptureOutput *)output;  // 添加輸出設(shè)備
 - (void)startRunning;   // 開始拍照
 - (void)stopRunning;  // 結(jié)束拍照

再添加設(shè)備之前以下方法應(yīng)該對你會有幫助

 - (BOOL)canAddInput:(AVCaptureInput *)input   
 - (BOOL)canAddOutput:(AVCaptureOutput *)output;

同上,調(diào)用拍照方法前請檢查相機(jī)連接設(shè)備,可能是這樣的

 - (AVCaptureConnection *)findVideoConnection {      /**< 相機(jī)連接設(shè)備*/
  AVCaptureConnection *videoConnection = nil;
  for (AVCaptureConnection *connection in self.stillImageOutput.connections) {
    for (AVCaptureInputPort *port in connection.inputPorts) {
      if ([[port mediaType] isEqual:AVMediaTypeVideo]) {
        videoConnection = connection;
        break;
      }
    }
    if (videoConnection) {
      break;
    }
  }
  return videoConnection;
}

2.AVCaptureVideoPreviewLayer

照相視圖顯示的layer,繼承與CALayer
你需要做以下基本設(shè)置:

 - (instancetype)initWithSession:(AVCaptureSession *)session;  // 關(guān)聯(lián)AVCaptureSession
@property CGRect frame; // 設(shè)置frame
 - (void)addSublayer:(CALayer *)layer;  // 添加sublayer

3.AVCaptureDeviceInput

照相輸入設(shè)備
你需要做以下基本設(shè)置:

+ (instancetype)deviceInputWithDevice:(AVCaptureDevice *)device error:(NSError **)outError;   // 初始化

以下代碼可能對你有所幫助

NSArray *devices = [AVCaptureDevice devices];
AVCaptureDevice *backCamera;
AVCaptureDevice *frontCamera;
for (AVCaptureDevice *device in devices) {
  if ([device hasMediaType:AVMediaTypeVideo]) {
    if ([device position] == AVCaptureDevicePositionBack) {
      backCamera = device;
    } else if ([device position] == AVCaptureDevicePositionFront) {
      frontCamera = device;
    }
  }
}

4.AVCaptureStillImageOutput

照片輸出設(shè)備
你需要做以下基本設(shè)置:

- (instancetype)init;  // 初始化
@property(nonatomic, copy) NSDictionary *outputSettings;  // 設(shè)置輸出類型它可能是這樣的@{AVVideoCodecKey : AVVideoCodecJPEG}
- (void)captureStillImageAsynchronouslyFromConnection:(AVCaptureConnection *)connection completionHandler:(void (^)(CMSampleBufferRef imageDataSampleBuffer, NSError *error))handler;  // 實現(xiàn)這個異步的方法,就可以拿到照片了,在這個方法中可以對照片進(jìn)行修改,并且把照片回調(diào)出去

以下代碼可能對你有所幫助

NSData *imgData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
UIImage *originImg = [UIImage imageWithData:imgData];

至此一個相機(jī)的基本拍照功能已經(jīng)全部完成


In order to set hardware properties on an AVCaptureDevice, such as focusMode and exposureMode, clients must first acquire a lock on the device. Clients should only hold the device lock if they require settable device propertiesto remain unchanged.

參考以上說明,你在對相機(jī)做對焦,閃光燈,縮放等等功能時候必須給AVCaptureDevice上鎖,像這樣

- (BOOL)lockForConfiguration:(NSError **)outError;  // 操作之前
- (void)unlockForConfiguration; // 操作完成之后

1.對焦

if ([device lockForConfiguration:nil]) {
  CGPoint pointOfInterest = [self pointOfInterestWithTouchPoint:touchPoint];// 點(diǎn)擊point在屏幕中的坐標(biāo)
    if (device.focusPointOfInterestSupported) {  // 聚焦
      device.focusPointOfInterest = pointOfInterest;
    }
    if (device.exposurePointOfInterestSupported) {  // 曝光
      device.exposurePointOfInterest = pointOfInterest;
    }
    if ([device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) {    
      device.focusMode = AVCaptureFocusModeContinuousAutoFocus;
    }
    if ([device isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]) {
      device.exposureMode = AVCaptureExposureModeContinuousAutoExposure;
    }
    [device unlockForConfiguration];
}

2.縮放,請參考
@property(nonatomic) CGFloat videoZoomFactor
建議關(guān)聯(lián)pan手勢的代理

3.閃光燈,請參考
@property(nonatomic) AVCaptureFlashMode flashMode
默認(rèn)是AVCaptureFlashModeAuto
設(shè)置AVCaptureFlashModeOnAVCaptureFlashModeOff切換

4.前后攝像頭切換,請參考
@property(nonatomic, readonly) AVCaptureDevicePosition position
可以通過移除輸入設(shè)備后再添加的方式


2.視圖類

自定義照相界面,你需要一個可愛的產(chǎn)品和設(shè)計,如果你的產(chǎn)品足夠仔細(xì),或者對原生相機(jī)功能情有獨(dú)鐘,他可能有這樣的需求

1.照片時候閃屏的效果,它可能是通過這樣實現(xiàn)

CABasicAnimation *twinkleAnim = [CABasicAnimation animationWithKeyPath:@"opacity"];
twinkleAnim.fromValue = @(1);
twinkleAnim.toValue = @(0);
twinkleAnim.duration = 0.2;
[self.view.layer addAnimation:twinkleAnim forKey:nil];

2.外接物理按鍵,比如聲音的放大縮小按鍵,它可能是這樣實現(xiàn)的

NSError *error;
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[[AVAudioSession sharedInstance] setActive:YES error:&error];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(volumeClick) name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil];
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];

監(jiān)聽系統(tǒng)音量通知,在volumeClick的方法中調(diào)用拍照的方法

如果你通過音量鍵拍照的時候看到了這個令你感到不愉快的東西,請繼續(xù)往下看

點(diǎn)擊拍照出現(xiàn)默認(rèn)音量界面

導(dǎo)入庫 MediaPlayer.framework
導(dǎo)入頭文件 #import <MediaPlayer/MediaPlayer.h>
自定義這個視圖,并把它放到屏幕外面,像這樣:

MPVolumeView *volumeView = [[MPVolumeView alloc]initWithFrame:CGRectMake(-20, -40, 10, 10)];
volumeView.hidden = NO;
[self.view addSubview:volumeView];

如果有更好的方法或者建議,以及文中的缺陷,希望大家可以留言告知,虛心求教
如果轉(zhuǎn)載本文,請注明本文出處,感謝

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容