import UIKit
设置扫码成功回调代理
@objc public protocol ShgQrCodeScanDelegate {
@objc optional func shgQrCodeScanFinished(_ strValue:String) -> Void
}
二维码识别使用 AVCaptureMetadataOutput
@objc public class ShgQrCodeScan: UIView ,AVCaptureMetadataOutputObjectsDelegate{
@objc public weak var deleagte:ShgQrCodeScanDelegate?
private lazy var session: AVCaptureSession = {
let session = AVCaptureSession.init()
if session.canSetSessionPreset(.high) {
session.sessionPreset = .high
}
return session
}()
private lazy var capLayer:AVCaptureVideoPreviewLayer = {
let layer = AVCaptureVideoPreviewLayer.init(session: self.session)
layer.videoGravity = .resizeAspectFill
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:AVCaptureMetadataOutput = {
let output = AVCaptureMetadataOutput.init()
return output
}()
/// 设备权限
/// - Returns: 授权状态
@objc public func deviceStatus() -> AVAuthorizationStatus {
let status = AVCaptureDevice.authorizationStatus(for: .video)
return status
}
@objc 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()
self.capOutput.metadataObjectTypes = [.qr , .code128]
//设置识别区域,竖屏右顶点为坐标原点,w,h 0-1
//绘制的页面识别区域 CGRect(x: (self.bounds.size.width - 200)/2, y: (self.bounds.size.height - 200)/2, width: 200, height: 200)
let x:CGFloat = ((self.bounds.size.width - 200)/2)/self.bounds.size.width
let y:CGFloat = ((self.bounds.size.height - 200)/2)/self.bounds.size.height
let width:CGFloat = 200.0/self.bounds.size.width
let height:CGFloat = 200.0/self.bounds.size.height
self.capOutput.rectOfInterest = CGRect(x: y,y: x,width: height,height: width)
self.capOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.global())
}
public override func layoutSubviews() {
self.capLayer.frame = self.bounds
}
//绘制识别区域
public override func draw(_ rect: CGRect) {
self.setLine(CGRect(x: (self.bounds.size.width - 200)/2, y: (self.bounds.size.height - 200)/2, width: 30, height: 30), edg: .top_letf)
self.setLine(CGRect(x: (self.bounds.size.width + 200)/2 - 30, y: (self.bounds.size.height - 200)/2, width: 30, height: 30), edg: .top_right)
self.setLine(CGRect(x: (self.bounds.size.width + 200)/2 - 30, y: (self.bounds.size.height + 200)/2 - 30, width: 30, height: 30), edg: .bot_right)
self.setLine(CGRect(x: (self.bounds.size.width - 200)/2, y: (self.bounds.size.height + 200)/2 - 30, width: 30, height: 30), edg: .bot_left)
}
enum Edge:Int{
case top_letf = 0
case top_right = 1
case bot_left = 2
case bot_right = 3
}
func setLine(_ rect:CGRect,edg:Edge) {
let shlayer = CAShapeLayer.init()
shlayer.frame = rect
shlayer.lineWidth = 2
shlayer.strokeColor = UIColor.green.cgColor
shlayer.fillColor = UIColor.clear.cgColor
shlayer.lineCap = .round
shlayer.lineJoin = .round
let bzp = UIBezierPath.init()
if edg == .top_letf {
bzp.move(to: CGPoint(x: 0, y: rect.size.height))
bzp.addLine(to: CGPoint(x: 0, y: 0))
bzp.addLine(to: CGPoint(x: rect.size.width, y: 0))
}
if edg == .top_right {
bzp.move(to: CGPoint(x: 0, y: 0))
bzp.addLine(to: CGPoint(x: rect.size.width, y: 0))
bzp.addLine(to: CGPoint(x: rect.size.width, y: rect.size.height))
}
if edg == .bot_left {
bzp.move(to: CGPoint(x: 0, y: 0))
bzp.addLine(to: CGPoint(x: 0, y: rect.size.height))
bzp.addLine(to: CGPoint(x: rect.size.width, y: rect.size.height))
}
if edg == .bot_right {
bzp.move(to: CGPoint(x: 0, y: rect.size.height))
bzp.addLine(to: CGPoint(x: rect.size.width, y: rect.size.height))
bzp.addLine(to: CGPoint(x: rect.size.width, y: 0))
}
shlayer.path = bzp.cgPath
self.layer.addSublayer(shlayer)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
extension ShgQrCodeScan {
public func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
self.session.stopRunning()
if metadataObjects.count == 0 {
return
}
if let metaData:AVMetadataMachineReadableCodeObject = metadataObjects.first as? AVMetadataMachineReadableCodeObject {
if metaData.type == .qr || metaData.type == .code128 {
let str:String = metaData.stringValue ?? ""
print(str)
if self.deleagte != nil {
self.deleagte!.shgQrCodeScanFinished?(str)
}
}
}
}
/// 识别图片中的二维码
/// - Parameter image: 二维码图片
/// - Returns: 二维码内容
@objc public func readQrCode(image:UIImage) -> String? {
let ctx:CIContext = CIContext.init()
guard let detec:CIDetector = CIDetector.init(ofType: CIDetectorTypeQRCode , context: ctx, options: [CIDetectorAccuracy:CIDetectorAccuracyLow]) else {
return nil
}
guard let ciImage:CIImage = CIImage.init(image: image) else {
return nil
}
let f:Array<CIFeature> = detec.features(in: ciImage)
if f.count == 0 {
return nil
}
if let codef:CIQRCodeFeature = f.first as? CIQRCodeFeature {
return codef.messageString
}
return nil
}
}
网友评论