iOS_从相机或相册里扫描二维码或条形码

news/2024/7/20 22:11:00 标签: ios, swift, 开发语言, xcode

文章目录

    • 1. 从相机里扫描
      • 1.1 申请相机权限
      • 1.2 创建Scanner
      • 1.3 开始扫描
      • 1.4 处理扫描结果
    • 2. 从相册里扫描
      • 2.1 获取相册权限
      • 2.2 打开相册
      • 2.3 获得选择结果
      • 2.4 解析相片中的二维码或条形码


1. 从相机里扫描

1.1 申请相机权限

  • 导入: import AVFoundation
  • 在项目的 Info.plist 文件里添加 Privacy - Camera Usage Descriptio 描述申请使用相机权限。
  • 查询相机权限: AVCaptureDevice.authorizationStatus(for: .video)
  • 权限类型:AVAuthorizationStatus
swift">notDetermined   未申请
restricted      受限制
denied          已拒绝
authorized      已授权
  • 请求相机权限,系统弹出授权申请提示:
swift">AVCaptureDevice.requestAccess(for: .video) { (status) in
    // handle request result
}

1.2 创建Scanner

  • 获得设备:
swift"> guard let device = AVCaptureDevice.default(for: .video) else {
    print("device error")
    return
}
  • 创建input:
swift"> let input: AVCaptureDeviceInput
do {
  input = try AVCaptureDeviceInput(device: device)
} catch {
  print("input error")
  return
}
if self.captureSession.canAddInput(input) {
    self.captureSession.addInput(input)
} else {
    print("session can't add input")
    return
}
  • 创建 output:
swift">let output = AVCaptureMetadataOutput()
if self.captureSession.canAddOutput(output) {
    // Tips: add output must before of set output
    self.captureSession.addOutput(output)
} else {
    print("session can't add output")
    return
}

// Set metadata identification type qr: QR code; Other: Barcode
// 设置扫描类型(qr:二维码,其他:条形码)
let hopeSupportTypes = [AVMetadataObject.ObjectType.qr,
                        AVMetadataObject.ObjectType.ean13,
                        AVMetadataObject.ObjectType.ean8,
                        AVMetadataObject.ObjectType.pdf417]
var types: [AVMetadataObject.ObjectType] = []
for type in hopeSupportTypes {
    if output.availableMetadataObjectTypes.contains(type) {
        types.append(type)
    }
}
output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
output.metadataObjectTypes = types        
output.rectOfInterest = CGRect(x: 0, y: 0,
                               width: self.view.bounds.size.width,
                               height: self.view.bounds.size.height)
  • 设置预览视图:
swift">let previewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession)
previewLayer.frame = scanView.layer.bounds
previewLayer.videoGravity = .resizeAspectFill
scanView.layer.addSublayer(previewLayer)

1.3 开始扫描

Tips: 不能在主线程中扫描,否则会无法响应用户操作,导致卡死现象

swift">DispatchQueue.global(qos: .userInitiated).async {
    self.captureSession.startRunning()
}

1.4 处理扫描结果

遵循 AVCaptureMetadataOutputObjectsDelegate 协议,实现扫描回调方法:

swift"> func metadataOutput(_ output: AVCaptureMetadataOutput,
                    didOutput metadataObjects: [AVMetadataObject],
                    from connection: AVCaptureConnection) {
    guard let metadataObject = metadataObjects.first else {
        captureSession.stopRunning()
        return
    }
    guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else {
        print("as? AVMetadataMachineReadableCodeObject faliue")
        return
    }
    guard let stringValue = readableObject.stringValue else {
        print("stringValue faliue")
        return
    }
    AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
    print("scan result: \(stringValue)")   // print result
    captureSession.stopRunning()
}

2. 从相册里扫描

2.1 获取相册权限

  • 导入: import Photos
  • 在项目的 Info.plist 文件里添加 Privacy - Photo Library Usage Description 描述申请访问相册权限。
  • 查询相机权限:PHPhotoLibrary.authorizationStatus()
  • 权限类型:PHAuthorizationStatus
swift">notDetermined   未申请
restricted      受限制
denied          已拒绝
authorized      已授权
limited         已授权有限库访问
  • 请求相册权限,系统弹出授权申请提示:
swift">PHPhotoLibrary.requestAuthorization { (status) in
    // handle request result
}

2.2 打开相册

Tips: 打开相册必须在主线程中执行

swift"> /// have photos permission
DispatchQueue.main.async {
    self.openPhotoLabrary()
}

private func openPhotoLabrary() {
    let picker = UIImagePickerController()
    picker.title = "Photos"
    picker.delegate = self
    picker.allowsEditing = true
    picker.sourceType = .photoLibrary
    picker.navigationBar.barStyle = .default
    self.present(picker, animated: true, completion: nil)
}

2.3 获得选择结果

遵循 UIImagePickerControllerDelegateUINavigationControllerDelegate 协议,并实现选中相片后触发的协议方法:

swift">func imagePickerController(_ picker: UIImagePickerController,
                           didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    dismiss(animated: true)
    
    guard let image = info[.originalImage] as? UIImage else {
        print("choose not image")
        return
    }
    parseBarCode(image: image)
}

2.4 解析相片中的二维码或条形码

导入:import Vision

swift"> /// parse qrCode or barCode
private func parseBarCode(image: UIImage) {
    guard let cgimg = image.cgImage else {
        return
    }
    
    let request = VNDetectBarcodesRequest { req, err in
        if let error = err {
            print("parseBarCode error: \(error)")
            return
        }
        self.handleResults(req.results)
    }
    
    let handler = VNImageRequestHandler(cgImage: cgimg)
    do {
        try handler.perform([request])
    } catch {
        print("parseBarCode error: \(error)")
    }
}

private func handleResults(_ result: [VNObservation]?) {
    guard let results = result, results.count > 0 else {
        print("parseBarCode result is nil: \(String(describing: result))")
        return
    }
    for result in results {
        self.handleResult(result)
    }
}

private func handleResult(_ result: VNObservation) {
    guard let barcode = result as? VNBarcodeObservation,
          let value = barcode.payloadStringValue else {
        print("handleResult covert to string error: \(result)")
        return
    }
    
    if barcode.symbology == .qr {
        print("二维码: \(value)")
    } else {
        print("条形码: \(value), \(barcode.symbology.rawValue)")
    }
}

github demo


参考:
iOS16 Swift二维码/条形码扫描+相册获取识别


http://www.niftyadmin.cn/n/187594.html

相关文章

LC-1638. 统计只差一个字符的子串数目(中心扩散法)

1638. 统计只差一个字符的子串数目 难度中等62 给你两个字符串 s 和 t ,请你找出 s 中的非空子串的数目,这些子串满足替换 一个不同字符 以后,是 t 串的子串。换言之,请你找到 s 和 t 串中 恰好 只有一个字符不同的子字符串对的…

Vue.js事件修饰符及v-model双向数据绑定

目录 一、事件修饰符 (1).stop阻止事件冒泡 (2).prevent阻止默认事件 (3).capture事件捕获模式 (4).self自身触发事件 (5).once事件只触发一次 二、v-…

vs2010下 转换到 COFF 期间失败: 文件无效或损坏

因为同一个电脑上安装多个VS,有多个cvtres.exe。按照下面的操作如果还是不行就在C盘搜索cvtres.exe,然后挨个重命名,看看是调用的哪个,然后修改就可以了。 用VS2010编译C项目时出现这样的错误: LNK1123: 转换到 COFF …

Linux 系统安装 Pytorch

文章目录配置 Anaconda下载 Anaconda安装 Anaconda配置 Pytorch创建虚环境安装 Pytorch配置 Anaconda 下载 Anaconda (1)网页方式下载离线包 进入 Anaconda 官网 ,出现如下的页面。 Anaconda 会根据访问网页所使用的系统,推荐对…

关于 Transformer 的面试题

面试题 请解释一下Transformer模型的注意力机制是如何工作的。 请解释一下Transformer模型中的编码器和解码器的作用是什么。 请简要解释一下Transformer模型与传统的循环神经网络模型的区别。 Transformer模型是否适用于非序列数据的任务?请举一个例子。 请解释…

一起来学5G终端射频标准(TAE for UL-MIMO)

01—TAE的定义我们先来了解一下TAE测试标准的发展演变。在4G LTE的3GPP 36.101-1的技术要求规范中,就给出了对4G终端UL MIMO以及V2X UE的TAE的定义和最小要求,但在36.521-1的4G终端一致性测试规范中并没有对应的章节规定TAE的一致性测试。5G中有所变化&a…

day17—选择题

文章目录1.下列sql语句中哪条语句可为用户zhangsan分配数据库userdb表userinfo的查询和插入数据权限(A)2.在手机开发中常用的数据库是(A)3.下列哪个特性与此事相关:已落实的事务会保证所有操作均已完成,并且…

【LeetCode】前 K 个高频元素(堆)

目录 1.题目要求: 给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。 2.解题思路: 代码展示: 1.题目要求: 给你一个整数数组 nums 和一个整数 k &#xff0…