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

2020-11-02  本文已影响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

上一篇下一篇

猜你喜欢

热点阅读