美文网首页
iOS 二维码扫描识别,二维码图片识别,原生处理

iOS 二维码扫描识别,二维码图片识别,原生处理

作者: 移动的键盘 | 来源:发表于2020-12-02 12:41 被阅读0次
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
}
}

相关文章

网友评论

      本文标题:iOS 二维码扫描识别,二维码图片识别,原生处理

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