iOS开发技巧之自定义相机
最近公司的项目中用到了相机,由于不用系统的相机,ui给的相机切图,必须自定义才可以。就花时间简单研究了一下相机的自定义。
相机属于系统硬件,这就需要我们来手动调用iphone的相机硬件,分为以下步骤:
1、首先声明以下对象
#import <avfoundation/avfoundation.h> //捕获设备,通常是前置摄像头,后置摄像头,麦克风(音频输入) @property (nonatomic, strong) avcapturedevice *device; //avcapturedeviceinput 代表输入设备,他使用avcapturedevice 来初始化 @property (nonatomic, strong) avcapturedeviceinput *input; //输出图片 @property (nonatomic ,strong) avcapturestillimageoutput *imageoutput; //session:由他把输入输出结合在一起,并开始启动捕获设备(摄像头) @property (nonatomic, strong) avcapturesession *session; //图像预览层,实时显示捕获的图像 @property (nonatomic ,strong) avcapturevideopreviewlayer *previewlayer;
2、初始化各个对象
- (void)cameradistrict { // avcapturedevicepositionback 后置摄像头 // avcapturedevicepositionfront 前置摄像头 self.device = [self camerawithposition:avcapturedevicepositionfront]; self.input = [[avcapturedeviceinput alloc] initwithdevice:self.device error:nil]; self.imageoutput = [[avcapturestillimageoutput alloc] init]; self.session = [[avcapturesession alloc] init]; // 拿到的图像的大小可以自行设定 // avcapturesessionpreset320x240 // avcapturesessionpreset352x288 // avcapturesessionpreset640x480 // avcapturesessionpreset960x540 // avcapturesessionpreset1280x720 // avcapturesessionpreset1920x1080 // avcapturesessionpreset3840x2160 self.session.sessionpreset = avcapturesessionpreset640x480; //输入输出设备结合 if ([self.session canaddinput:self.input]) { [self.session addinput:self.input]; } if ([self.session canaddoutput:self.imageoutput]) { [self.session addoutput:self.imageoutput]; } //预览层的生成 self.previewlayer = [[avcapturevideopreviewlayer alloc] initwithsession:self.session]; self.previewlayer.frame = cgrectmake(0, 64, screen_width, screen_height-64); self.previewlayer.videogravity = avlayervideogravityresizeaspectfill; [self.view.layer addsublayer:self.previewlayer]; //设备取景开始 [self.session startrunning]; if ([_device lockforconfiguration:nil]) { //自动闪光灯, if ([_device isflashmodesupported:avcaptureflashmodeauto]) { [_device setflashmode:avcaptureflashmodeauto]; } //自动白平衡,但是好像一直都进不去 if ([_device iswhitebalancemodesupported:avcapturewhitebalancemodeautowhitebalance]) { [_device setwhitebalancemode:avcapturewhitebalancemodeautowhitebalance]; } [_device unlockforconfiguration]; } }
根据前后置位置拿到相应的摄像头:
- (avcapturedevice *)camerawithposition:(avcapturedeviceposition)position{ nsarray *devices = [avcapturedevice deviceswithmediatype:avmediatypevideo]; for ( avcapturedevice *device in devices ) if ( device.position == position ){ return device; } return nil; }
3、拍照拿到相应图片:
- (void)photobtndidclick { avcaptureconnection *conntion = [self.imageoutput connectionwithmediatype:avmediatypevideo]; if (!conntion) { nslog(@"拍照失败!"); return; } [self.imageoutput capturestillimageasynchronouslyfromconnection:conntion completionhandler:^(cmsamplebufferref imagedatasamplebuffer, nserror *error) { if (imagedatasamplebuffer == nil) { return ; } nsdata *imagedata = [avcapturestillimageoutput jpegstillimagensdatarepresentation:imagedatasamplebuffer]; self.image = [uiimage imagewithdata:imagedata]; [self.session stoprunning]; [self.view addsubview:self.cameraimageview]; }
4、保存照片到相册:
#pragma - 保存至相册 - (void)saveimagetophotoalbum:(uiimage*)savedimage { uiimagewritetosavedphotosalbum(savedimage, self, @selector(image:didfinishsavingwitherror:contextinfo:), null); } // 指定回调方法 - (void)image: (uiimage *) image didfinishsavingwitherror: (nserror *) error contextinfo: (void *) contextinfo { nsstring *msg = nil ; if(error != null){ msg = @"保存图片失败" ; }else{ msg = @"保存图片成功" ; } uialertview *alert = [[uialertview alloc] initwithtitle:@"保存图片结果提示" message:msg delegate:self cancelbuttontitle:@"确定" otherbuttontitles:nil]; [alert show]; }
5、前后置摄像头的切换
- (void)changecamera{ nsuinteger cameracount = [[avcapturedevice deviceswithmediatype:avmediatypevideo] count]; if (cameracount > 1) { nserror *error; //给摄像头的切换添加翻转动画 catransition *animation = [catransition animation]; animation.duration = .5f; animation.timingfunction = [camediatimingfunction functionwithname:kcamediatimingfunctioneaseineaseout]; animation.type = @"oglflip"; avcapturedevice *newcamera = nil; avcapturedeviceinput *newinput = nil; //拿到另外一个摄像头位置 avcapturedeviceposition position = [[_input device] position]; if (position == avcapturedevicepositionfront){ newcamera = [self camerawithposition:avcapturedevicepositionback]; animation.subtype = kcatransitionfromleft;//动画翻转方向 } else { newcamera = [self camerawithposition:avcapturedevicepositionfront]; animation.subtype = kcatransitionfromright;//动画翻转方向 } //生成新的输入 newinput = [avcapturedeviceinput deviceinputwithdevice:newcamera error:nil]; [self.previewlayer addanimation:animation forkey:nil]; if (newinput != nil) { [self.session beginconfiguration]; [self.session removeinput:self.input]; if ([self.session canaddinput:newinput]) { [self.session addinput:newinput]; self.input = newinput; } else { [self.session addinput:self.input]; } [self.session commitconfiguration]; } else if (error) { nslog(@"toggle carema failed, error = %@", error); } } }
6、相机的其它参数设置
//avcaptureflashmode 闪光灯 //avcapturefocusmode 对焦 //avcaptureexposuremode 曝光 //avcapturewhitebalancemode 白平衡 //闪光灯和白平衡可以在生成相机时候设置 //曝光要根据对焦点的光线状况而决定,所以和对焦一块写 //point为点击的位置 - (void)focusatpoint:(cgpoint)point{ cgsize size = self.view.bounds.size; cgpoint focuspoint = cgpointmake( point.y /size.height ,1-point.x/size.width ); nserror *error; if ([self.device lockforconfiguration:&error]) { //对焦模式和对焦点 if ([self.device isfocusmodesupported:avcapturefocusmodeautofocus]) { [self.device setfocuspointofinterest:focuspoint]; [self.device setfocusmode:avcapturefocusmodeautofocus]; } //曝光模式和曝光点 if ([self.device isexposuremodesupported:avcaptureexposuremodeautoexpose ]) { [self.device setexposurepointofinterest:focuspoint]; [self.device setexposuremode:avcaptureexposuremodeautoexpose]; } [self.device unlockforconfiguration]; //设置对焦动画 _focusview.center = point; _focusview.hidden = no; [uiview animatewithduration:0.3 animations:^{ _focusview.transform = cgaffinetransformmakescale(1.25, 1.25); }completion:^(bool finished) { [uiview animatewithduration:0.5 animations:^{ _focusview.transform = cgaffinetransformidentity; } completion:^(bool finished) { _focusview.hidden = yes; }]; }]; } }
7、遇到的一些坑和解决办法
1) 前后置摄像头的切换
前后值不能切换,各种尝试找了半天没找到有原因。后来发现我在设置图片尺寸的时候设置为1080p [self.session cansetsessionpreset: avcapturesessionpreset1920x1080] ,前置摄像头并不支持这么大的尺寸,所以就不能切换前置摄像头。我验证了下 前置摄像头最高支持720p,720p以内可*切换。
当然也可以在前后置摄像头切换的时候,根据前后摄像头来设置不同的尺寸,这里不在赘述。
2)焦点位置
cgpoint focuspoint = cgpointmake( point.y /size.height ,1-point.x/size.width );
setexposurepointofinterest:focuspoint 函数后面point取值范围是取景框左上角(0,0)到取景框右下角(1,1)之间。官方是这么写的:
the value of this property is a cgpoint that determines the receiver's focus point of interest, if it has one. a value of (0,0) indicates that the camera should focus on the top left corner of the image, while a value of (1,1) indicates that it should focus on the bottom right. the default value is (0.5,0.5).
我也试了按这个来但位置就是不对,只能按上面的写法才可以。前面是点击位置的y/previewlayer的高度,后面是1-点击位置的x/previewlayer的宽度
3)对焦和曝光
我在设置对焦是 先设置了模式setfocusmode,后设置对焦位置,就会导致很奇怪的现象,对焦位置是你上次点击的位置。所以一定要先设置位置,再设置对焦模式。
曝光同上
8、写在最后
附上demo:photographdemo
常用到的基本就这么多,写的并不完善,有什么不对的,欢迎大家批评指正,共同学习。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 姜茶退烧吗,有什么样的功效呢