iOS自定義相機

本文對之前做過的相機模塊做個小結,包括自定義相機拍照界面,照片處理及保存等,感興趣的朋友可以做個參考

如果你要執(zhí)行以下操作,你應該使用該系統(tǒng)API來構建自定義相機:

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

準備工作

1.添加plist配置相機權限
2.判斷有無權限

AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];

如果未申請過權限,則進行權限獲取

[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
            dispatch_sync(dispatch_get_main_queue(), ^{
                if (granted) {
                   // 申請權限成功
                } else {
                    // 申請權限失敗
                }
            });
        }];
  1. 如果默認橫屏,需要根據屏幕方向進行旋轉

自定義相機配置信息

需要創(chuàng)建以下屬性

//捕獲設備,通常是前置攝像頭,后置攝像頭,麥克風(音頻輸入)
@property(nonatomic) AVCaptureDevice *device;
//session會話 由它把輸入輸出結合在一起,并開始啟動捕獲設備(攝像頭)
@property(nonatomic) AVCaptureSession *session;
//AVCaptureDeviceInput 代表輸入設備,使用AVCaptureDevice 來初始化
@property(nonatomic) AVCaptureDeviceInput *input;
//照片輸出流
@property (nonatomic) AVCapturePhotoOutput *imageOutPut;
//圖像預覽層,實時顯示捕獲的圖像
@property(nonatomic) AVCaptureVideoPreviewLayer *previewLayer;
  1. 初始化session會話,用來結合輸入輸出
self.session = [[AVCaptureSession alloc] init];
    if ([self.session canSetSessionPreset:AVCaptureSessionPreset1280x720]) {
        [self.session setSessionPreset:AVCaptureSessionPreset1280x720];  //拿到的圖像的大小可以自行設定
    }
  1. 獲取視頻輸入設備(攝像頭)
self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
  1. 創(chuàng)建視頻輸入源 并添加到會話
self.input = [[AVCaptureDeviceInput alloc]initWithDevice:self.device error:nil];
    if ([self.session canAddInput:self.input]) {
        [self.session addInput:self.input];
    }
  1. 創(chuàng)建視頻輸出源 并添加到會話
self.imageOutPut = [[AVCapturePhotoOutput alloc]init];
    if ([self.session canAddOutput:self.imageOutPut]) {
        [self.session addOutput:self.imageOutPut];
    }
    AVCaptureConnection *imageConnection = [self.imageOutPut connectionWithMediaType:AVMediaTypeVideo];
    // 設置 imageConnection 控制相機拍攝圖片的角度方向
    if (imageConnection.supportsVideoOrientation) {
        imageConnection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
    }
  1. 初始化預覽層,session會話負責驅動input輸入源進行信息的采集,layer預覽層負責把采集到的圖像進行渲染顯示
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. 開始采集界面
[self.session startRunning];

拍照屬性設置 (可選項)

需要先加鎖在進行設置

if ([self.device lockForConfiguration:nil]) { // 修改設備的屬性,先加鎖
       
        ……設置內容……
        //解鎖
        [self.device unlockForConfiguration];
    }
  1. 聚焦
// 添加聚焦手勢
- (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 函數后面Point取值范圍是取景框左上角(0,0)到取景框右下角(1,1)之間,有時按這個來但位置不對,按實際適配
    CGPoint focusPoint = CGPointMake( point.x /size.width , point.y/size.height );
    if ([self.device lockForConfiguration:nil]) {
        [self.session beginConfiguration];
        /*****必須先設定聚焦位置,在設定聚焦方式******/
        //聚焦點的位置
        if ([self.device isFocusPointOfInterestSupported]) {
            [self.device setFocusPointOfInterest:focusPoint];
        }
        // 聚焦模式
        if ([self.device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
            [self.device setFocusMode:AVCaptureFocusModeAutoFocus];
        }else{
            NSLog(@"聚焦模式修改失敗");
        }
        //曝光點的位置
        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. 白平衡
 //自動白平衡
        if ([self.device isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeAutoWhiteBalance]) {
            [self.device setWhiteBalanceMode:AVCaptureWhiteBalanceModeAutoWhiteBalance];
        }
  1. 切換攝像頭
//獲取攝像頭的數量
    NSUInteger cameraCount = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo] count];
    //攝像頭小于等于1的時候直接返回
    if (cameraCount <= 1) return;
    AVCaptureDevice *newCamera = nil;
    AVCaptureDeviceInput *newInput = nil;
    //獲取當前相機的方向(前還是后)
    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];
        //先移除原來的input
        [self.session removeInput:self.input];
        if ([self.session canAddInput:newInput]) {
            [self.session addInput:newInput];
            self.input = newInput;
        } else {
            //如果不能加現在的input,就加原來的input
            [self.session addInput:self.input];
        }
        [self.session commitConfiguration];
    }
  1. 閃光燈配置
if ([[self.imageOutPut supportedFlashModes] containsObject:@(AVCaptureFlashModeOn)]) {
         self.imageOutPut.photoSettingsForSceneMonitoring.flashMode = AVCaptureFlashModeOn;             
 }
  1. 手電筒配置
//獲取當前相機的方向(前還是后) 前置攝像頭不允許開啟手電筒
    AVCaptureDevicePosition position = [[self.input device] position];
    if (position == AVCaptureDevicePositionFront) {
        NSLog(@"前置攝像時無法開啟手電筒");
        return;
    }
    AVCaptureDevice *device = self.device;
    if ([device hasTorch]) { // 判斷是否有閃光燈
        // 請求獨占訪問硬件設備
        [device lockForConfiguration:nil];
        if (sender.selected == NO) {
            sender.selected = YES;
            [device setTorchMode:AVCaptureTorchModeOn]; // 手電筒開
        } else {
            sender.selected = NO;
            [device setTorchMode:AVCaptureTorchModeOff]; // 手電筒關
        }
        // 請求解除獨占訪問硬件設備
        [device unlockForConfiguration];
    }

拍照獲取圖片

  1. 拍照操作
AVCaptureConnection * videoConnection = [self.imageOutPut connectionWithMediaType:AVMediaTypeVideo];
    if (videoConnection ==  nil) {
        return;
    }
    AVCapturePhotoSettings *set = [AVCapturePhotoSettings photoSettings];
    [self.imageOutPut capturePhotoWithSettings:set delegate:self];
  1. 通過代理方法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];
    }
}

獲取到圖片需要進行處理,前置攝像頭需處理左右成像問題
例:

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. 保存到相冊
//存儲
    [[PHPhotoLibrary sharedPhotoLibrary]performChanges:^{
        [PHAssetChangeRequest creationRequestForAssetFromImage:fixImage];
    } completionHandler:^(BOOL success, NSError * _Nullable error) {
        if (error) {
            NSLog(@"%@",@"保存失敗");
        } else {
            NSLog(@"%@",@"保存成功");
        }
    }];

其他

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

github項目地址: https://github.com/percival888/CustomCameraDemo

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

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

相關閱讀更多精彩內容

友情鏈接更多精彩內容