美文网首页
iOS 自定义简单相机,前后摄像头可切换,添加滤镜

iOS 自定义简单相机,前后摄像头可切换,添加滤镜

作者: 移动的键盘 | 来源:发表于2020-11-02 18:00 被阅读0次
    import UIKit
    @objc public class YXCamera: UIView {
        private lazy var session: AVCaptureSession = {
        let session = AVCaptureSession.init()
        session.sessionPreset = .high
        return session
    }()
    
    private lazy var capLayer:AVCaptureVideoPreviewLayer = {
        let layer = AVCaptureVideoPreviewLayer.init(session: self.session)
        layer.videoGravity = .resizeAspectFill
        layer.frame = self.bounds
        return layer
    }()
    
    private var device:AVCaptureDevice?
    
    private lazy var capInput:AVCaptureDeviceInput? = {
        if let device = AVCaptureDevice.default( .builtInWideAngleCamera, for: .video, position: .back) {
            do {
                try device.lockForConfiguration()
            } catch  {
                return nil
            }
            if device.isFocusModeSupported(.autoFocus) {
                device.focusMode = .autoFocus
            }
            device.unlockForConfiguration()
            self.device = device
            var input:AVCaptureDeviceInput?
            do {
                try input = AVCaptureDeviceInput.init(device: device)
            } catch {
                print(error)
            }
            return input
        }
        return nil
    }()
    
    private lazy var capOutput:AVCapturePhotoOutput = {
        let output = AVCapturePhotoOutput.init()
        return output
    }()
    
    private lazy var delegate:YXCameraDelgate = {
        let delegate:YXCameraDelgate = YXCameraDelgate.init()
        return delegate
    }()
    
    public override init(frame: CGRect) {
        super.init(frame: frame)
        if self.deviceStatus() != .authorized {
            print("未授权")
            return
        }
        if self.capInput == nil {
            print("捕捉设备输入异常")
            return
        }
        self.layer.addSublayer(self.capLayer)
        if self.session.canAddInput(self.capInput!) {
            self.session.addInput(self.capInput!)
        }
        if self.session.canAddOutput(self.capOutput) {
            self.session.addOutput(self.capOutput)
        }
        self.session.startRunning()
        
    }
    
    /// 设备权限
    /// - Returns: 授权状态
    @objc public func deviceStatus() -> AVAuthorizationStatus {
        let status = AVCaptureDevice.authorizationStatus(for: .video)
        return status
    }
    
    /// 开始拍照
    @objc public func start(backImage:@escaping((_:UIImage) -> Void)) {
        self.delegate.backimage = backImage
        let setting = AVCapturePhotoSettings.init(format: [AVVideoCodecKey:AVVideoCodecType.jpeg])
     //判断设备支持 Flash,并且 Flash 可用
        if self.device!.hasFlash && self.device!.isFlashAvailable {
            if self.capOutput.supportedFlashModes.contains(.auto) {
                setting.flashMode = .auto
            }
        }
        self.capOutput.capturePhoto(with: setting, delegate: self.delegate)
    }
    
    /// 切换前后摄像头
    /// - Parameter position: .front 前置  .back 后置
    /// - Returns: 设备捕捉输入
    @objc public func changeCam(position:AVCaptureDevice.Position) {
        if self.device!.position == position {
            return
        }
        if let device = AVCaptureDevice.default( .builtInWideAngleCamera, for: .video, position: position) {
            do {
                try device.lockForConfiguration()
            } catch  {
                print("异常",error)
                return
            }
            if device.isFocusModeSupported(.autoFocus) {
                device.focusMode = .autoFocus
            }
            device.unlockForConfiguration()
            self.device = device
            var input:AVCaptureDeviceInput?
            do {
                try input = AVCaptureDeviceInput.init(device: device)
            } catch {
                print("异常",error)
                return
            }
            if input != nil {
                //添加到session
                if self.session.inputs.contains(self.capInput!) {
                    self.session.removeInput(self.capInput!)
                    self.capInput = nil
                }
                self.capInput = input
                if self.session.canAddInput(self.capInput!) {
                    self.session.addInput(self.capInput!)
                }
                
                //添加切换动画
                let animation:CATransition = CATransition.init()
                animation.duration = 0.5
                animation.timingFunction = CAMediaTimingFunction.init(name: .easeInEaseOut)
                animation.type = CATransitionType(rawValue: "cameraIrisHollowOpen")
                if position == .front {
                    animation.subtype = .fromRight
                } else if position == .back {
                    animation.subtype = .fromLeft
                }
                self.capLayer.removeAllAnimations()
                self.capLayer.add(animation, forKey: nil)
                
            } else {
                print("摄像头切换失败")
            }
        }
    }
    
    /// 打开手电筒
    /// - Parameter torchMode: public enum TorchMode : Int { case off = 0 case on = 1 case auto = 2 }
    @objc public func openTorch(_ torchMode:AVCaptureDevice.TorchMode) {
        if self.device!.hasTorch && self.device!.isTorchAvailable {
            if self.device!.isTorchModeSupported(torchMode) {
                do {
                    try self.device!.lockForConfiguration()
                } catch {
                    print("手电筒打开异常",error)
                    return
                }
                self.device!.torchMode = torchMode
                self.device!.unlockForConfiguration()
            }
        } else {
            print("手电筒不可用")
        }
    }
    
    /// 判断手电筒状态
    /// - Returns: true 打开状态  false 关闭状态
    @objc public func isTorchActive() -> Bool {
        return self.device!.isTorchActive
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    }
    
    // MARK: -- 处理AVCapturePhotoCaptureDelegate代理回调
    class YXCameraDelgate: NSObjec ,AVCapturePhotoCaptureDelegate {
    var backimage:((_:UIImage) -> ())?
    public func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        guard let data = photo.fileDataRepresentation() else { return }
        guard let image = UIImage.init(data: data) else { return }
        UIImageWriteToSavedPhotosAlbum(image, self, #selector(saveImage(image:didFinishSavingWithError:contextInfo:)), nil)
        if self.backimage != nil {
            self.backimage!(image)
        }
    }
    @objc private func saveImage(image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: AnyObject) {
        if error != nil{
            print("保存失败",error!)
        }else{
            print("保存成功")
        }
    }
    }
    

    /// 滤镜

    @objc public class YXFilter: CIFilter {
    
    /// 获取所有的滤镜
    /// - Parameter category: 滤镜扩展
    /// - Returns: 某个扩展里所有的滤镜
    /// [kCICategoryDistortionEffect, 扭曲效果,比如bump、旋转、hole
    /// kCICategoryGeometryAdjustment, 几何开着调整,比如仿射变换、平切、透视转换
    /// kCICategoryCompositeOperaCIFiltertion, 合并,比如源覆盖(source over)、最小化、源在顶(source atop)、色彩混合模式
    /// kCICategoryHalftoneEffect, Halftone效果,比如screen、line screen、hatched
    /// kCICategoryColorAdjustment, 色彩调整,比如伽马调整、白点调整、曝光
    /// kCICategoryColorEffect, 色彩效果,比如色调调整、posterize
    /// kCICategoryTransition, 图像间转换,比如dissolve、disintegrate with mask、swipe
    /// kCICategoryTileEffect, 瓦片效果,比如parallelogram、triangle
    /// kCICategoryGenerator, 图像生成器,比如stripes、constant color、checkerboard
    /// kCICategoryReduction, 一种减少图像数据的过滤器。这些过滤器是用来解决图像分析问题
    /// kCICategoryGradient, 渐变,比如轴向渐变、仿射渐变、高斯渐变
    /// kCICategoryStylize, 风格化,比如像素化、水晶化
    /// kCICategorySharpen, 锐化、发光
    /// kCICategoryBlur, 模糊,比如高斯模糊、焦点模糊、运动模糊
    /// kCICategoryVideo, 能用于视频
    /// kCICategoryStillImage, 能用于静态图像
    /// kCICategoryInterlaced, 能用于交错图像
    /// kCICategoryNonSquarePixels, 能用于非矩形像素
    /// kCICategoryHighDynamicRange, 能用于HDR
    /// kCICategoryBuiltIn, 获取所有coreImage 内置滤镜
    /// kCICategoryFilterGenerator,  通过链接几个过滤器并将其打包为CIFilterGenerator对象而创建的过滤器]
    @objc public class func filterNamesinCategory(category: String) -> [String] {
        return YXFilter.filterNames(inCategory: category)
    }
    
    /// 给图片添加滤镜
    /// - Parameters:
    ///   - filterName: 滤镜名
    ///   - image: 原始图片
    /// - Returns: 目标图片
    @objc public class func filterToImage(filterName:String,image:UIImage) -> UIImage? {
       
        let ciImage = CIImage.init(image: image)
        let filter:YXFilter = YXFilter.init(name: filterName)!
        guard filter.inputKeys.contains("inputImage") else {
            return nil
        }
        filter.setValue(ciImage, forKey: "inputImage")
        guard let outputImage:CIImage = filter.outputImage else {
            return nil
        }
        guard let glContext:EAGLContext = EAGLContext.init(api: .openGLES2) else {
            return nil
        }
        let context:CIContext = CIContext.init(eaglContext: glContext)
        guard let cgimage:CGImage = context.createCGImage(outputImage, from: outputImage.extent) else {
            return nil
        }
        let newImage:UIImage = UIImage.init(cgImage: cgimage, scale: image.scale, orientation: image.imageOrientation)
        return newImage
    }
    }
    

    Dome:https://github.com/ShaoGangGitHub/YXCamera.git

    相关文章

      网友评论

          本文标题:iOS 自定义简单相机,前后摄像头可切换,添加滤镜

          本文链接:https://www.haomeiwen.com/subject/ieimvktx.html