这是公司上上上一个项目的自定义相机界面,原来是swift2.0写的,今天改为swift3.0,记录一下.

效果图如下:

                                                                                                                                                                                                                      

使用AVFoundation制作.

属性:

 1     var device:AVCaptureDevice!   //获取设备:如摄像头
 2     var input:AVCaptureDeviceInput!   //输入流
 3     var photoOutput:AVCaptureStillImageOutput! //输出流
 4     var  output:AVCaptureMetadataOutput! //当启动摄像头开始捕获输入
 5     var  session:AVCaptureSession!//会话,协调着intput到output的数据传输,input和output的桥梁
 6     var  previewLayer:AVCaptureVideoPreviewLayer! //图像预览层,实时显示捕获的图像
 7     
 8     var photoButton: UIButton?   //拍照按钮
 9     var imageView: UIImageView?   //拍照后的成像
10     var image: UIImage?   //拍照后的成像
11     var isJurisdiction: Bool?   //是否获取了拍照标示
12     var flashBtn:UIButton?  //闪光灯按钮

在viewDidLoad里面判断下权限,没给权限给个提示

        isJurisdiction = canUserCamear()
        if isJurisdiction! {
            customCamera()  //自定义相机
            customUI()  //自定义相机按钮
        }
        else {
            return
        }
    // MARK: - 检查相机权限
    func canUserCamear() -> Bool {
        let authStatus: AVAuthorizationStatus = AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo)
        if authStatus == .denied {
            let alertView = UIAlertView(title: "请打开相机权限", message: "设置-隐私-相机", delegate: self, cancelButtonTitle: "确定", otherButtonTitles: "取消")
            alertView.tag = 100
            alertView.show()
            return false
        }
        else {
            return true
        }
        return true
    }

自定义相机:

 1  //MARK: 初始化自定义相机
 2     func customCamera(){
 3        guard let devices = AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo) as? [AVCaptureDevice] else { return } //初始化摄像头设备
 4         guard let device = devices.filter({ return $0.position == .back }).first else{ return}
 5         self.device = device
 6         //输入流初始化
 7         self.input = try? AVCaptureDeviceInput(device: device)
 8         //照片输出流初始化
 9         self.photoOutput = AVCaptureStillImageOutput.init()
10         //输出流初始化
11         self.output = AVCaptureMetadataOutput.init()
12         //生成会话
13         self.session = AVCaptureSession.init()
14         if(self.session.canSetSessionPreset("AVCaptureSessionPreset1280x720")){
15             self.session.sessionPreset = "AVCaptureSessionPreset1280x720"
16         }
17         if(self.session.canAddInput(self.input)){
18             self.session.addInput(self.input)
19         }
20         if(self.session.canAddOutput(self.photoOutput)){
21             self.session.addOutput(self.photoOutput)
22         }
23         //使用self.session,初始化预览层,self.session负责驱动input进行信息的采集,layer负责把图像渲染显示
24         self.previewLayer = AVCaptureVideoPreviewLayer.init(session: self.session)
25         self.previewLayer.frame  = CGRect.init(x: 0, y: 0, width: kScreenWH.width, height: kScreenWH.height)
26         self.previewLayer.videoGravity = "AVLayerVideoGravityResizeAspectFill"
27         self.view.layer.addSublayer(self.previewLayer)
28         //启动
29         self.session.startRunning()
30         if ((try? device.lockForConfiguration()) != nil) {
31             if device.isFlashModeSupported(.auto) {
32                 device.flashMode = .auto
33             }
34             //自动白平衡
35             if device.isWhiteBalanceModeSupported(.autoWhiteBalance) {
36                 device.whiteBalanceMode = .autoWhiteBalance
37             }
38             device.unlockForConfiguration()
39         }
40         
41         //闪光灯
42         do{ try device.lockForConfiguration() }catch{ }
43         if device.hasFlash == false { return }
44         device.flashMode = AVCaptureFlashMode.auto
45         device.unlockForConfiguration()
46         
47     }
View Code

自定义相机界面按钮:拍照,取消,闪光灯,前后拍照切换按钮

 1 //MARK: 添加自定义按钮等UI
 2     func customUI(){
 3        //前后摄像头切换
 4         let changeBtn = UIButton.init()
 5         changeBtn.frame = CGRect.init(x: kScreenWH.width - 50, y: 20, width: 40, height: 40)
 6         changeBtn.setImage(#imageLiteral(resourceName: "change"), for: .normal)
 7         changeBtn.addTarget(self, action: #selector(self.changeCamera), for: .touchUpInside)
 8         view.addSubview(changeBtn)
 9         
10         //拍照按钮
11         photoButton = UIButton(type: .custom)
12         photoButton?.frame = CGRect(x: kScreenWH.width * 1 / 2.0 - 30, y: kScreenWH.height - 100, width: 60, height: 60)
13         photoButton?.setImage(UIImage(named: "photograph"), for: .normal)
14         photoButton?.setImage(UIImage(named: "photograph_Select"), for: .normal)
15         photoButton?.addTarget(self, action: #selector(self.shutterCamera), for: .touchUpInside)
16         view.addSubview(photoButton!)
17         
18       //闪光灯按钮
19         flashBtn = UIButton.init()
20         flashBtn?.frame = CGRect.init(x: 10, y: 20, width: 40, height: 40)
21         flashBtn?.addTarget(self, action: #selector(self.flashAction), for: .touchUpInside)
22         flashBtn?.setImage(#imageLiteral(resourceName: "flash-A"), for: .normal)
23         view.addSubview(flashBtn!)
24         
25        //取消
26         let cancelBtn = UIButton.init()
27         cancelBtn.frame = CGRect.init(x: 10, y: kScreenWH.height - 100, width: 60, height: 60)
28         cancelBtn.setTitle("取消", for: .normal)
29         cancelBtn.addTarget(self, action: #selector(self.cancelActin), for: .touchUpInside)
30         view.addSubview(cancelBtn)
31     }
32     //MARK:前后摄像头更改事件
33     func changeCamera(){
34         //获取之前的镜头
35         guard var position = input?.device.position else { return }
36         //获取当前应该显示的镜头
37         position = position == .front ? .back : .front
38         //创建新的device
39         guard let devices = AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo) as? [AVCaptureDevice] else { return }
40         // 1.2.取出获取前置摄像头
41         let d = devices.filter({ return $0.position == position }).first
42         device = d
43         //input
44         guard let videoInput = try? AVCaptureDeviceInput(device: d) else { return }
45 
46         //切换
47         session.beginConfiguration()
48         session.removeInput(self.input!)
49         session.addInput(videoInput)
50         session.commitConfiguration()
51         self.input = videoInput
52         
53     }
View Code

拍照按钮点击事件:

 1     //MARK:拍照按钮点击事件
 2     func shutterCamera(){
 3         let videoConnection: AVCaptureConnection? = photoOutput.connection(withMediaType: AVMediaTypeVideo)
 4         if videoConnection == nil {
 5             print("take photo failed!")
 6             return
 7         }
 8         photoOutput.captureStillImageAsynchronously(from: videoConnection ?? AVCaptureConnection(), completionHandler: {(_ imageDataSampleBuffer: CMSampleBuffer?, _ error: Error?) -> Void in
 9             if imageDataSampleBuffer == nil {
10                 return
11             }
12             let imageData: Data? = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer)   //照片数据流
13             self.image = UIImage(data: imageData!)
14             self.session.stopRunning()
15             self.imageView = UIImageView(frame: self.previewLayer.frame)
16             self.view.insertSubview(self.imageView!, belowSubview: self.photoButton!)
17             self.imageView?.layer.masksToBounds = true
18             self.imageView?.image = self.image
19             print("image size = \(NSStringFromCGSize((self.image?.size)!))")
20         })
21     }
View Code

闪光灯切换事件:

 1     //MARK: 闪光灯开关
 2     func flashAction(){
 3         try? device.lockForConfiguration()
 4         switch device.flashMode.rawValue {
 5         case 0:
 6             device!.flashMode = AVCaptureFlashMode.on
 7             flashBtn?.setImage(#imageLiteral(resourceName: "flash-on"), for: .normal)
 8             break
 9         case 1:
10         device!.flashMode = AVCaptureFlashMode.auto
11         flashBtn?.setImage(#imageLiteral(resourceName: "flash-A"), for: .normal)
12             break
13         default:
14          device!.flashMode = AVCaptureFlashMode.off
15             flashBtn?.setImage(#imageLiteral(resourceName: "flash-off"), for: .normal)
16         }
17         device.unlockForConfiguration()
18         
19     }
View Code

取消按钮点击事件:

    //MARK:取消按钮
    func cancelActin(){
        self.imageView?.removeFromSuperview()
        self.session.startRunning()
    }

github源码地址:https://github.com/pheromone/swift_custom_camera