首頁 > 軟體

iOS自定義相機功能

2022-07-20 18:01:53

大多數app都會涉及到上傳照片這個功能,圖片來源無非是從相簿獲取或者相機拍攝。如果不是特別要求,呼叫系統已經滿足需求。但對於特殊需求,就需要自定義相機拍攝介面了。

對於無需客製化的相機,使用系統的UIKit庫裡的UIImagePickerController類,幾行程式碼,幾個代理方法就可滿足所需。但如果要深度客製化,就要系統庫AVFoundation內部的相關類。

建立自己的相機管理類CameraManager(繼承於NSObject)

.h檔案

#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
//拍照後的回撥,傳遞拍攝的照片
typedef void(^DidCapturePhotoBlock)(UIImage *stillImage);

@interface PXCameraManager : NSObject

@property (nonatomic, strong) AVCaptureSession *session;//AVCaptureSession物件來執行輸入裝置和輸出裝置之間的資料傳遞

@property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer;//預覽圖層,來顯示照相機拍攝到的畫面

@property (nonatomic, strong) AVCaptureDeviceInput *deviceInput;//AVCaptureDeviceInput物件是輸入流

@property (nonatomic, strong) AVCaptureStillImageOutput *stillImageOutput;//照片輸出流物件

@property (nonatomic, assign) CGRect previewLayerFrame;//拍照區域

/* 為其他類提供的自定義介面 */

//設定拍照區域 (其中targetView為要展示拍照介面的view)
- (void)configureWithtargetViewLayer:(UIView *)targetView previewRect:(CGRect)preivewRect;

//拍照成功回撥
- (void)takePicture:(DidCapturePhotoBlock)block;

//新增/移除相機浮層(如果有需求要在相機拍照區域新增浮層的時候使用)
- (void)addCoverImageWithImage:(UIImage *)image;
- (void)removeCoverImageWithImage:(UIImage *)image;

//前後攝像頭切換
- (void)switchCameras;

//閃光燈切換
- (void)configCameraFlashlight;


@end

.m檔案

@property (nonatomic, strong) UIView *preview;//展現拍照區域的view
@property (nonatomic, strong) UIImageView *coverImageView;//拍照區域浮層

@property (nonatomic, assign) BOOL isCaremaBack;
@property (nonatomic, assign) AVCaptureFlashMode flashMode;

//初始化的時候設定自己想要的預設屬性
- (instancetype)init{

    self = [super init];
    if (self) {

        self.isCaremaBack = YES;//預設後置攝像頭
        self.flashMode = AVCaptureFlashModeAuto;//預設自動閃光燈
    }
    return  self;
}

實現介面的方法

1、準備相關硬體

- (void)configureWithTargetViewLayer:(UIView *)targetView previewRect:(CGRect)preivewRect{

    self.preview = targetView;

    //開始一些相機相關硬體設定    
    [self addSession];//建立session

    [self addVideoPreviewLayerWithRect:preivewRect];//用session 建立 建立layer

    [self addvideoInputBackCamera:self.isCaremaBack];//給session 設定攝像頭

    [self addVideoFlashlightWithFlashModel:self.flashMode];//設定閃光燈

    [self addStillImageOutput];//給session 設定輸出
}

2、拍照

#pragma mark - 
- (void)takePicture:(DidCapturePhotoBlock)block{

    AVCaptureConnection *captureConnection = [self findCaptureConnection];

    [captureConnection setVideoScaleAndCropFactor:1.0f];

    [_stillImageOutput captureStillImageAsynchronouslyFromConnection:captureConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {

        NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];

        UIImage *image = [UIImage imageWithData:imageData];
        //這裡可以根據不同需求對拍攝到的照片做一些壓縮或者裁剪的處理,這裡我就偷懶不弄了。
        if (block) {
            block(image);
        }
    }];

}

3、切換攝像頭

- (void)switchCameras{
    if (!_deviceInput) {
        return;
    }
    [_session beginConfiguration];

    [_session removeInput:_deviceInput];
    self.isCaremaBack = !self.isCaremaBack;
    [self addvideoInputBackCamera:self.isCaremaBack];

    [_session commitConfiguration];
}

4、切換閃光燈

- (void)configCameraFlashlight{

    switch (self.flashMode) {
        case AVCaptureFlashModeAuto:
        {
            self.flashMode = AVCaptureFlashModeOff;
        }
            break;
        case AVCaptureFlashModeOff:
        {
            self.flashMode = AVCaptureFlashModeOn;
        }
            break;
        case AVCaptureFlashModeOn:
        {
            self.flashMode = AVCaptureFlashModeAuto;
        }
            break;
        default:
            break;
    }

    [self addVideoFlashlightWithFlashModel:self.flashMode];

 }

新增/移除 浮層

- (void)addCoverImageWithImage:(UIImage *)image{

    _coverImageView.image = image;
}
- (void)removeCoverImageWithImage:(UIImage *)image{

    _coverImageView.image = nil;

}

下面是設定硬體裡的幾個方法實現

- (void)addSession{

    if (!self.session) {
        AVCaptureSession *session = [[AVCaptureSession alloc]init];
        self.session = session;
    }
}
- (void)addVideoPreviewLayerWithRect:(CGRect)previewRect{

    if (!self.previewLayer) {
        AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc]initWithSession:_session];
        previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;

        self.previewLayer = previewLayer;

        [self.preview.layer addSublayer:self.previewLayer];

    }

    self.previewLayer.frame = previewRect;
}
- (void)addvideoInputBackCamera:(BOOL)back{

    NSArray *devices = [AVCaptureDevice devices];

    AVCaptureDevice *frontCamera;
    AVCaptureDevice *backCamera;
    //獲取 前、後 攝像頭
    for (AVCaptureDevice *device in devices) {

        if ([device hasMediaType:AVMediaTypeVideo]) {

            if ([device position] == AVCaptureDevicePositionBack) {

                backCamera = device;

            }else if([device position] == AVCaptureDevicePositionFront){

                frontCamera = device;

            }
        }
    }

    NSError *error = nil;


    if(back){
        AVCaptureDeviceInput *backCameraDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:backCamera error:&error];
        if (!error) {

            if ([_session canAddInput:backCameraDeviceInput]) {

                [_session addInput:backCameraDeviceInput];
                 self.deviceInput = backCameraDeviceInput;

            }else{
                NSLog(@"出錯啦");
            }
        }

    }else{

        AVCaptureDeviceInput *frontCameraDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:frontCamera error:&error];
        if (!error) {

            if ([_session canAddInput:frontCameraDeviceInput]) {

                [_session addInput:frontCameraDeviceInput];
                 self.deviceInput = frontCameraDeviceInput;

            }else{
                NSLog(@"出錯啦");
            }
        }
    }


}
- (void)addVideoFlashlightWithFlashModel:(AVCaptureFlashMode )flashModel{

    AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    [device lockForConfiguration:nil];

    if ([device hasFlash]) {
        device.flashMode = self.flashMode;
    }

    [device unlockForConfiguration];
}
- (void)addStillImageOutput{

    if (!self.stillImageOutput) {

        AVCaptureStillImageOutput *stillImageOutput = [[AVCaptureStillImageOutput alloc]init];
        NSDictionary *outPutSettingDict = [[NSDictionary alloc]initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey, nil];
        stillImageOutput.outputSettings = outPutSettingDict;

        [_session addOutput:stillImageOutput];

        self.stillImageOutput = stillImageOutput;
    }


}
- (AVCaptureConnection *)findCaptureConnection{


    AVCaptureConnection *videoConnection;

    for (AVCaptureConnection *connection in _stillImageOutput.connections ) {
        for (AVCaptureInputPort *port in connection.inputPorts) {

            if ([[port mediaType] isEqual:AVMediaTypeVideo]) {

                videoConnection = connection;

                return videoConnection;
            }
        }
    }

    return nil;

}

到此,一個自定義相機的類就有了,要使用的時候,儘管呼叫吧。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com