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