iOS随笔——自定义照相机

1.工具类(CameraManager)

一个自定义照相机的工具类你可能需要以下功能:
这个工具类看起来可能是这样的:

  • 用户相机授权检测
 + (BOOL)checkAuthority;
  • 通过一个自定义视图初始化
 - (instancetype)initWithCameraCustomView:(UIView *)customView;
  • 拍照结束的照片返回可以是代理或者block
 - (void)takePhotoWithImageBlock:(void(^)(UIImage *originImg, NSError *error))imageBlock;
  • 开始/结束拍照
  - (void)startCamera; 
  - (void)stopCamera;
  • 闪光灯、聚焦、缩放、前后摄像头切换、照片裁剪加工等等

自定义相机的实现基于AVFoundation框架

来源苹果官方,这里只关注照相功能
来源苹果官方,这里只关注照相功能

1.AVCaptureSession

自定义相机的核心类,主要用于建立输入流和输出流之间的联系。
你需要实现以下基本方法:

 - (void)addInput:(AVCaptureInput *)input;    // 添加输入设备
 - (void)addOutput:(AVCaptureOutput *)output;  // 添加输出设备
 - (void)startRunning;   // 开始拍照
 - (void)stopRunning;  // 结束拍照

再添加设备之前以下方法应该对你会有帮助

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

同上,调用拍照方法前请检查相机连接设备,可能是这样的

 - (AVCaptureConnection *)findVideoConnection {      /**< 相机连接设备*/
  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
你需要做以下基本设置:

 - (instancetype)initWithSession:(AVCaptureSession *)session;  // 关联AVCaptureSession
@property CGRect frame; // 设置frame
 - (void)addSublayer:(CALayer *)layer;  // 添加sublayer

3.AVCaptureDeviceInput

照相输入设备
你需要做以下基本设置:

+ (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

照片输出设备
你需要做以下基本设置:

- (instancetype)init;  // 初始化
@property(nonatomic, copy) NSDictionary *outputSettings;  // 设置输出类型它可能是这样的@{AVVideoCodecKey : AVVideoCodecJPEG}
- (void)captureStillImageAsynchronouslyFromConnection:(AVCaptureConnection *)connection completionHandler:(void (^)(CMSampleBufferRef imageDataSampleBuffer, NSError *error))handler;  // 实现这个异步的方法,就可以拿到照片了,在这个方法中可以对照片进行修改,并且把照片回调出去

以下代码可能对你有所帮助

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

至此一个相机的基本拍照功能已经全部完成


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.

参考以上说明,你在对相机做对焦,闪光灯,缩放等等功能时候必须给AVCaptureDevice上锁,像这样

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

1.对焦

if ([device lockForConfiguration:nil]) {
  CGPoint pointOfInterest = [self pointOfInterestWithTouchPoint:touchPoint];// 点击point在屏幕中的坐标
    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
建议关联pan手势的代理

3.闪光灯,请参考
@property(nonatomic) AVCaptureFlashMode flashMode
默认是AVCaptureFlashModeAuto
设置AVCaptureFlashModeOnAVCaptureFlashModeOff切换

4.前后摄像头切换,请参考
@property(nonatomic, readonly) AVCaptureDevicePosition position
可以通过移除输入设备后再添加的方式


2.视图类

自定义照相界面,你需要一个可爱的产品和设计,如果你的产品足够仔细,或者对原生相机功能情有独钟,他可能有这样的需求

1.照片时候闪屏的效果,它可能是通过这样实现

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

2.外接物理按键,比如声音的放大缩小按键,它可能是这样实现的

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];

监听系统音量通知,在volumeClick的方法中调用拍照的方法

如果你通过音量键拍照的时候看到了这个令你感到不愉快的东西,请继续往下看

点击拍照出现默认音量界面

导入库 MediaPlayer.framework
导入头文件 #import <MediaPlayer/MediaPlayer.h>
自定义这个视图,并把它放到屏幕外面,像这样:

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

如果有更好的方法或者建议,以及文中的缺陷,希望大家可以留言告知,虚心求教
如果转载本文,请注明本文出处,感谢

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容