iOS自定義相機(jī)

本文對(duì)之前做過(guò)的相機(jī)模塊做個(gè)小結(jié),包括自定義相機(jī)拍照界面,照片處理及保存等,感興趣的朋友可以做個(gè)參考

如果你要執(zhí)行以下操作,你應(yīng)該使用該系統(tǒng)API來(lái)構(gòu)建自定義相機(jī):

構(gòu)建自定義的相機(jī)用戶界面,將拍照或視頻錄制集成到應(yīng)用中
為用戶提供對(duì)照片和視頻捕獲更直接的控制,例如焦點(diǎn),曝光等增強(qiáng)選項(xiàng)。
與系統(tǒng)相機(jī) UI 產(chǎn)生不同的結(jié)果,例如 RAW 格式的照片,深度圖或需要自定義視頻元數(shù)據(jù)
從采集設(shè)備 (Capture device) 實(shí)時(shí)獲取視頻像素或音頻數(shù)據(jù)。

準(zhǔn)備工作

1.添加plist配置相機(jī)權(quán)限
2.判斷有無(wú)權(quán)限

AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];

如果未申請(qǐng)過(guò)權(quán)限,則進(jìn)行權(quán)限獲取

[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
            dispatch_sync(dispatch_get_main_queue(), ^{
                if (granted) {
                   // 申請(qǐng)權(quán)限成功
                } else {
                    // 申請(qǐng)權(quán)限失敗
                }
            });
        }];
  1. 如果默認(rèn)橫屏,需要根據(jù)屏幕方向進(jìn)行旋轉(zhuǎn)

自定義相機(jī)配置信息

需要?jiǎng)?chuàng)建以下屬性

//捕獲設(shè)備,通常是前置攝像頭,后置攝像頭,麥克風(fēng)(音頻輸入)
@property(nonatomic) AVCaptureDevice *device;
//session會(huì)話 由它把輸入輸出結(jié)合在一起,并開(kāi)始啟動(dòng)捕獲設(shè)備(攝像頭)
@property(nonatomic) AVCaptureSession *session;
//AVCaptureDeviceInput 代表輸入設(shè)備,使用AVCaptureDevice 來(lái)初始化
@property(nonatomic) AVCaptureDeviceInput *input;
//照片輸出流
@property (nonatomic) AVCapturePhotoOutput *imageOutPut;
//圖像預(yù)覽層,實(shí)時(shí)顯示捕獲的圖像
@property(nonatomic) AVCaptureVideoPreviewLayer *previewLayer;
  1. 初始化session會(huì)話,用來(lái)結(jié)合輸入輸出
self.session = [[AVCaptureSession alloc] init];
    if ([self.session canSetSessionPreset:AVCaptureSessionPreset1280x720]) {
        [self.session setSessionPreset:AVCaptureSessionPreset1280x720];  //拿到的圖像的大小可以自行設(shè)定
    }
  1. 獲取視頻輸入設(shè)備(攝像頭)
self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
  1. 創(chuàng)建視頻輸入源 并添加到會(huì)話
self.input = [[AVCaptureDeviceInput alloc]initWithDevice:self.device error:nil];
    if ([self.session canAddInput:self.input]) {
        [self.session addInput:self.input];
    }
  1. 創(chuàng)建視頻輸出源 并添加到會(huì)話
self.imageOutPut = [[AVCapturePhotoOutput alloc]init];
    if ([self.session canAddOutput:self.imageOutPut]) {
        [self.session addOutput:self.imageOutPut];
    }
    AVCaptureConnection *imageConnection = [self.imageOutPut connectionWithMediaType:AVMediaTypeVideo];
    // 設(shè)置 imageConnection 控制相機(jī)拍攝圖片的角度方向
    if (imageConnection.supportsVideoOrientation) {
        imageConnection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
    }
  1. 初始化預(yù)覽層,session會(huì)話負(fù)責(zé)驅(qū)動(dòng)input輸入源進(jìn)行信息的采集,layer預(yù)覽層負(fù)責(zé)把采集到的圖像進(jìn)行渲染顯示
self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
    self.previewLayer.frame = CGRectMake(0, 0, width,height);
    self.previewLayer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight; // 圖層展示拍攝角度方向
    self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    [self.view.layer addSublayer:self.previewLayer];
  1. 開(kāi)始采集界面
[self.session startRunning];

拍照屬性設(shè)置 (可選項(xiàng))

需要先加鎖在進(jìn)行設(shè)置

if ([self.device lockForConfiguration:nil]) { // 修改設(shè)備的屬性,先加鎖
       
        ……設(shè)置內(nèi)容……
        //解鎖
        [self.device unlockForConfiguration];
    }
  1. 聚焦
// 添加聚焦手勢(shì)
- (void)addTap {
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(focusGesture:)];
    [self.view addGestureRecognizer:tap];
}
- (void)focusGesture:(UITapGestureRecognizer*)gesture{
    CGPoint point = [gesture locationInView:gesture.view];
   CGSize size = self.view.bounds.size;
    // focusPoint 函數(shù)后面Point取值范圍是取景框左上角(0,0)到取景框右下角(1,1)之間,有時(shí)按這個(gè)來(lái)但位置不對(duì),按實(shí)際適配
    CGPoint focusPoint = CGPointMake( point.x /size.width , point.y/size.height );
    if ([self.device lockForConfiguration:nil]) {
        [self.session beginConfiguration];
        /*****必須先設(shè)定聚焦位置,在設(shè)定聚焦方式******/
        //聚焦點(diǎn)的位置
        if ([self.device isFocusPointOfInterestSupported]) {
            [self.device setFocusPointOfInterest:focusPoint];
        }
        // 聚焦模式
        if ([self.device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
            [self.device setFocusMode:AVCaptureFocusModeAutoFocus];
        }else{
            NSLog(@"聚焦模式修改失敗");
        }
        //曝光點(diǎn)的位置
        if ([self.device isExposurePointOfInterestSupported]) {
            [self.device setExposurePointOfInterest:focusPoint];
        }
        //曝光模式
        if ([self.device isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]) {
            [self.device setExposureMode:AVCaptureExposureModeContinuousAutoExposure];
        } else {
            NSLog(@"曝光模式修改失敗");
        }
        [self.device unlockForConfiguration];
        [self.session commitConfiguration];
    }
}
  1. 白平衡
 //自動(dòng)白平衡
        if ([self.device isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeAutoWhiteBalance]) {
            [self.device setWhiteBalanceMode:AVCaptureWhiteBalanceModeAutoWhiteBalance];
        }
  1. 切換攝像頭
//獲取攝像頭的數(shù)量
    NSUInteger cameraCount = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo] count];
    //攝像頭小于等于1的時(shí)候直接返回
    if (cameraCount <= 1) return;
    AVCaptureDevice *newCamera = nil;
    AVCaptureDeviceInput *newInput = nil;
    //獲取當(dāng)前相機(jī)的方向(前還是后)
    AVCaptureDevicePosition position = [[self.input device] position];
    if (position == AVCaptureDevicePositionFront) {
        //獲取后置攝像頭
        newCamera = [self cameraWithPosition:AVCaptureDevicePositionBack];
    }else{
        //獲取前置攝像頭
        newCamera = [self cameraWithPosition:AVCaptureDevicePositionFront];
    }
    [self.previewLayer addAnimation:animation forKey:nil];
    //輸入流
    newInput = [AVCaptureDeviceInput deviceInputWithDevice:newCamera error:nil];
    if (newInput != nil) {
        [self.session beginConfiguration];
        //先移除原來(lái)的input
        [self.session removeInput:self.input];
        if ([self.session canAddInput:newInput]) {
            [self.session addInput:newInput];
            self.input = newInput;
        } else {
            //如果不能加現(xiàn)在的input,就加原來(lái)的input
            [self.session addInput:self.input];
        }
        [self.session commitConfiguration];
    }
  1. 閃光燈配置
if ([[self.imageOutPut supportedFlashModes] containsObject:@(AVCaptureFlashModeOn)]) {
         self.imageOutPut.photoSettingsForSceneMonitoring.flashMode = AVCaptureFlashModeOn;             
 }
  1. 手電筒配置
//獲取當(dāng)前相機(jī)的方向(前還是后) 前置攝像頭不允許開(kāi)啟手電筒
    AVCaptureDevicePosition position = [[self.input device] position];
    if (position == AVCaptureDevicePositionFront) {
        NSLog(@"前置攝像時(shí)無(wú)法開(kāi)啟手電筒");
        return;
    }
    AVCaptureDevice *device = self.device;
    if ([device hasTorch]) { // 判斷是否有閃光燈
        // 請(qǐng)求獨(dú)占訪問(wèn)硬件設(shè)備
        [device lockForConfiguration:nil];
        if (sender.selected == NO) {
            sender.selected = YES;
            [device setTorchMode:AVCaptureTorchModeOn]; // 手電筒開(kāi)
        } else {
            sender.selected = NO;
            [device setTorchMode:AVCaptureTorchModeOff]; // 手電筒關(guān)
        }
        // 請(qǐng)求解除獨(dú)占訪問(wèn)硬件設(shè)備
        [device unlockForConfiguration];
    }

拍照獲取圖片

  1. 拍照操作
AVCaptureConnection * videoConnection = [self.imageOutPut connectionWithMediaType:AVMediaTypeVideo];
    if (videoConnection ==  nil) {
        return;
    }
    AVCapturePhotoSettings *set = [AVCapturePhotoSettings photoSettings];
    [self.imageOutPut capturePhotoWithSettings:set delegate:self];
  1. 通過(guò)代理方法captureOutput:didFinishProcessingPhoto:error:獲取到圖片
-(void)captureOutput:(AVCapturePhotoOutput *)output didFinishProcessingPhoto:(AVCapturePhoto *)photo error:(NSError *)error {
    if (!error) {
        NSData *imageData = [photo fileDataRepresentation];
        UIImage *image = [UIImage imageWithData:imageData];
        //處理圖片
        [self handleOriginalImage:image];
    }
}

獲取到圖片需要進(jìn)行處理,前置攝像頭需處理左右成像問(wèn)題
例:

CGAffineTransform transform = CGAffineTransformIdentity;
            transform = CGAffineTransformTranslate(transform, aImage.size.height, aImage.size.width);
            transform = CGAffineTransformRotate(transform, M_PI);
            transform = CGAffineTransformTranslate(transform, aImage.size.height,0);
            transform = CGAffineTransformScale(transform, -1, 1);
            CGContextRef ctx =CGBitmapContextCreate(NULL, aImage.size.height, aImage.size.width,CGImageGetBitsPerComponent(aImage.CGImage),0,CGImageGetColorSpace(aImage.CGImage),CGImageGetBitmapInfo(aImage.CGImage));
            CGContextConcatCTM(ctx, transform);
            CGContextDrawImage(ctx,CGRectMake(0,0,aImage.size.height,aImage.size.width), aImage.CGImage);
            CGImageRef cgimg =CGBitmapContextCreateImage(ctx);
            img = [UIImage imageWithCGImage:cgimg];
            CGContextRelease(ctx);
            CGImageRelease(cgimg);
  1. 保存到相冊(cè)
//存儲(chǔ)
    [[PHPhotoLibrary sharedPhotoLibrary]performChanges:^{
        [PHAssetChangeRequest creationRequestForAssetFromImage:fixImage];
    } completionHandler:^(BOOL success, NSError * _Nullable error) {
        if (error) {
            NSLog(@"%@",@"保存失敗");
        } else {
            NSLog(@"%@",@"保存成功");
        }
    }];

其他

可以給圖片加水印,定位信息,拍攝時(shí)間信息等 給圖像添加信息需要使用文件存儲(chǔ),UIImage無(wú)法存儲(chǔ)資料

github項(xiàng)目地址: https://github.com/percival888/CustomCameraDemo

參考:
https://cloud.tencent.com/developer/article/1532831
https://blog.csdn.net/u010029439/article/details/113201454

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

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

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