class ScanViewController: BaseViewController {
typealias FeelBarCodeViewScanSuccess = (_ brandName:String?,_ cosName:String?) -> Void
var scanSuccess:FeelBarCodeViewScanSuccess?
//是否是第一次扫描到结果
var firstResult: Bool = true
//AVCaptureSession对象来执行输入设备和输出设备之间的数据传递
var session: AVCaptureSession?
//输入设备
var videoInput: AVCaptureDeviceInput?
//输出对象
var metadataOutput: AVCaptureMetadataOutput = AVCaptureMetadataOutput()
//预览图层
var previewLayer: AVCaptureVideoPreviewLayer?
var scanTimer: Timer?
//边框
lazy var borderView: UIImageView = UIImageView(image: UIImage(named:"scan_border"))
//line
lazy var scanLineView: UIImageView = UIImageView(image: UIImage(named: "scan_line"))
private let borderWidth = autoWidth(width: 400)
private let topMargin: CGFloat = autoHeight(height: 230)
override func viewDidLoad() {
super.viewDidLoad()
setupNav()
setupCaptureSession()
addSubviews()
scanTimer = Timer.scheduledTimer(timeInterval: 3.0, target: self, selector: #selector(startAnimation), userInfo: nil, repeats: true)
}
func setupNav() {
navigationItem.title = "扫一扫"
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "相册", style: .plain, target: self, action: #selector(albumAction))
}
//MARK:- 相册
@objc func albumAction() {
Utils.isRightAlbum { [weak self] (authorized) in
if authorized {
let picker = UIImagePickerController()
picker.sourceType = .photoLibrary
picker.delegate = self
picker.allowsEditing = false
self?.present(picker, animated: true, completion: nil)
}
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
firstResult = true
if let session = self.session {
session.startRunning()
}
scanTimer?.fireDate = NSDate.distantPast
}
//MARK:- 扫描结果
func getInfoWithCode(code: String?) -> Void {
if let url = code {
scanTimer?.fireDate = NSDate.distantFuture
let vc = AcquireBookViewController()
if url.contains(BASE_URL) {
vc.requestUrl = url
} else {
vc.isNotBookQR = true
}
navigationController?.pushViewController(vc, animated: true)
}
}
func addSubviews() {
let leftMargin: CGFloat = (SCREEN_WIDTH - borderWidth) * 0.5
let coverImageView = UIImageView(frame: CGRect(x: 0, y: navigationHigh(), width: SCREEN_WIDTH, height: SCREEN_HEIGHT - navigationHigh()))
coverImageView.backgroundColor = UIColor.clear
coverImageView.image = self.getCoverView(left: leftMargin, top: topMargin)
view.addSubview(coverImageView)
//扫描边框
borderView.frame = CGRect(x: leftMargin, y: navigationHigh() + topMargin, width: borderWidth, height: borderWidth)
view.addSubview(borderView)
//扫描的线
scanLineView.frame = CGRect(x: leftMargin, y: navigationHigh() + topMargin, width: borderWidth, height: 2)
view.addSubview(scanLineView)
let tipLabel = UILabel.createLabelWith(title: "将取景框对准二维码,即可自动扫描", titleColor: UIColor.white, fontSize: autoFont(size: 24), alignment: .center, lines: 0)
tipLabel.frame = CGRect(x: autoWidth(width: 40), y: borderView.frame.maxY + autoHeight(height: 40), width: SCREEN_WIDTH - autoWidth(width: 80), height: autoHeight(height: 40))
view.addSubview(tipLabel)
}
//MARK:生成背景遮盖
func getCoverView(left: CGFloat, top: CGFloat) -> UIImage? {
UIGraphicsBeginImageContext(CGSize(width: SCREEN_WIDTH, height: SCREEN_HEIGHT - navigationHigh()))
let contextRef = UIGraphicsGetCurrentContext()
contextRef?.setFillColor(Main_TextBlackColor.withAlphaComponent(0.3).cgColor)
contextRef?.fill(CGRect(x: 0, y: 0, width: SCREEN_WIDTH, height: SCREEN_HEIGHT))
let inset = autoWidth(width: 4)
contextRef?.clear(CGRect(x: left + inset, y: top + inset, width: SCREEN_WIDTH - left * 2 - inset * 2, height: SCREEN_WIDTH - left * 2 - inset * 2))
return UIGraphicsGetImageFromCurrentImageContext()
}
//MARK:- 开始扫描动画
@objc func startAnimation() -> Void {
//让约束从顶部开始
var frame = self.scanLineView.frame
frame.origin.y = navigationHigh() + topMargin
self.scanLineView.frame = frame
self.scanLineView.layoutIfNeeded()
UIView.animate(withDuration: 3.0, animations: {
//改变frame
frame.origin.y = navigationHigh() + self.topMargin + self.borderWidth
self.scanLineView.frame = frame
//强制更新界面
self.scanLineView.layoutIfNeeded()
})
}
func stopAnimation() -> Void {
//让约束从顶部开始
var frame = self.scanLineView.frame
frame.origin.y = navigationHigh() + topMargin
self.scanLineView.frame = frame
self.scanLineView.layoutIfNeeded()
scanTimer?.invalidate()
scanTimer = nil
}
//MARK:设置session
func setupCaptureSession() {
self.session = AVCaptureSession()
//高质量采集率
self.session?.sessionPreset = AVCaptureSession.Preset.high
guard let device = AVCaptureDevice.default(for: AVMediaType.video) else { return }
//更改这个设置的时候必须先锁定设备,修改完后再解锁,否则崩溃
do{
try device.lockForConfiguration()
//设置闪光灯为自动
device.flashMode = AVCaptureDevice.FlashMode.auto
device.unlockForConfiguration()
}catch{
print("崩溃")
}
do{
try self.videoInput = AVCaptureDeviceInput(device: device)
}catch{
print("崩溃")
}
//输入设备
if let videoInput = self.videoInput {
if self.session?.canAddInput(videoInput) == true {
self.session?.addInput(videoInput)
}
}
//添加输出
if self.session?.canAddOutput(self.metadataOutput) == true{
self.session?.addOutput(self.metadataOutput)
}
self.metadataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.qr,
AVMetadataObject.ObjectType.ean13,
AVMetadataObject.ObjectType.ean8,
AVMetadataObject.ObjectType.code128,
AVMetadataObject.ObjectType.code39,
AVMetadataObject.ObjectType.code93]
self.metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
//预览图层
if let session = self.session {
self.previewLayer = AVCaptureVideoPreviewLayer(session: session)
self.previewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
self.previewLayer?.frame = CGRect(x: 0, y : 0, width: SCREEN_WIDTH, height: SCREEN_HEIGHT)
}
if let layer = self.previewLayer {
view.layer.insertSublayer(layer, at: 0)
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
//关闭session
if let session = self.session{
session.stopRunning()
}
}
deinit {
scanTimer?.invalidate()
scanTimer = nil
print("scan-----deinit")
}
}
extension ScanViewController: AVCaptureMetadataOutputObjectsDelegate {
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
for current in metadataObjects {
if current.isKind(of: AVMetadataMachineReadableCodeObject.self) {
let code = current as! AVMetadataMachineReadableCodeObject
//码内容
if let codeContent = code.stringValue {
if firstResult == true {
session?.stopRunning()
// scanTimer?.invalidate()
// scanTimer = nil
getInfoWithCode(code: codeContent)
}
firstResult = false
}
}
}
}
}
extension ScanViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let type = info[UIImagePickerControllerMediaType] as? String
if type == "public.image" {
if let image = info["UIImagePickerControllerOriginalImage"] as? UIImage {
getInfoWithImage(image: image)
}
}
picker.dismiss(animated: true, completion: nil)
}
//MARK:- 解析图片
func getInfoWithImage(image: UIImage) {
let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh])
let features = detector?.features(in: CIImage(cgImage: image.cgImage!))
if features == nil || features!.count <= 0 {
dm_toast("没有可识别的二维码")
return
}
for feature in features! {
if let qrcode = feature as? CIQRCodeFeature {
getInfoWithCode(code: qrcode.messageString)
}
}
}
}
网友评论