自己的项目大多都是以OC写的,随着swift版本的更新和苹果的力推,学习swift成为刻不容缓的事情,今天我们就聊一下怎样实现一个二维码的扫描与生成,好了废话不多说,直接进入撸吗阶段
1.二维码的扫描()
1.1 导入AVFoundation框架
import AVFoundation
1.2设置扫描会话,输入,输出
//MARK:内部控制方法
private func scanQRcode()
{
//1.判断输入是否添加到会话中
if !session.canAddInput(input)
{
return
}
//2.判断输出能够添加到会话中
if !session.canAddOutput(outPut){
return
}
//3.添加输入和输出到会话中
session.addInput(input)
session.addOutput(outPut)
//4.设置输出能够与解析的数据类型
//注意点:设置数据类型一定要在输出对象添加之后才能设置
//availableMetadataObjectTypes解析所有类型的你也可以写自己相关类型的
outPut.metadataObjectTypes = outPut.availableMetadataObjectTypes
//5.设置监听,监听输出解析到数据()
outPut.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
//6.添加预览图层
view.layer.insertSublayer(previewLayer, at: 0)
previewLayer.frame = view.bounds
//7.开始扫描
session.startRunning()
}
//MARK:懒加载
//1.输入对象
private lazy var input: AVCaptureDeviceInput = {
let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
return try! AVCaptureDeviceInput(device: device)
}()
//2.会话
private lazy var session: AVCaptureMetadataOutput =
{
let out = AVCaptureMetadataOutput()
//设置输出对象解析数据是感兴趣的范围(二维码扫描范围)
//默认值是CGRect(x: 0, y: 0, width: 1, height: 1) 传入是比例,是以横屏左上角作(x,y)相反和竖屏为参照的
//获取屏幕的frame
let viewRect = self.view.frame
//获取扫描容器的frame
let containRect = self.containView.frame
let x = containRect.origin.y / viewRect.height
let y = containRect.origin.x / viewRect.width
let width = containRect.height / viewRect.height
let height = containRect.width / viewRect.width
out.rectOfInterest = CGRect(x: x, y: x, width: width, height: height)
return out
}()
//3.输出对象
private lazy var outPut:AVCaptureMetadataOutput = AVCaptureMetadataOutput()
//4.专门用于保存二维码描边的图层
lazy var containLayer: CALayer = CALayer()
//MARK:AVCaptureMetadataOutputObjectsDelegate代理
extension QRCodeViewController:AVCaptureMetadataOutputObjectsDelegate
{
//所有的内有都在metadataObjects
//1.显示扫描到的结果
let object = metadataObjects.last
guard let contentStr: String = (object as AnyObject).stringValue else {
return
}
//2.定位二维码()
clearLayers()//每次有数据都要清空之前的描边
//安全校验(拿到扫描数据)
guard let metadata = metadataObjects.last as? AVMetadataObject else {
return
}
//转换数据(二维码的点)
//通过预览图层将Corners转换为我们能识别的点
let objc = previewLayer.transformedMetadataObject(for: metadata)
//2.对扫描到二维码进行描边
drawLines(objc:(objc as? AVMetadataMachineReadableCodeObject)! )
}
//绘制描边
private func drawLines(objc:AVMetadataMachineReadableCodeObject)
{
clearLayers()
//安全校验
guard let array = objc.corners
else {
return
}
//1.创建图层
let layer = CAShapeLayer()
layer.lineWidth = 2
layer.strokeColor = UIColor.red.cgColor
layer.fillColor = UIColor.clear.cgColor
//2.创建UIbesizerPath
let path = UIBezierPath()
var point = CGPoint.zero
var index : Int = 0
point = CGPoint.init(dictionaryRepresentation: array[index] as! CFDictionary)!
index += 1
//2.1将起点移动到某一个点
path.move(to: point)
//2.2连接其他的片段
while index < array.count {
point = CGPoint.init(dictionaryRepresentation: array[index] as! CFDictionary)!
index += 1
path.addLine(to: point)
}
//2.3关闭路径
path.close()
layer.path = path.cgPath
//用于保存矩形的图层添加到界面上
containLayer.addSublayer(layer)
}
//清空描边
private func clearLayers()
{
guard let subLayers = containLayer.sublayers else {
return
}
for layer in subLayers {
layer.removeFromSuperlayer()
}
}
}
2.识别相册中的二维码
2.1建立相册,弹出相册
func initPhoto(){
//1.判断是否能够打开
if !UIImagePickerController.isSourceTypeAvailable(.photoLibrary)
{
return
}
//2.创建相册控制器
let imagePickVc = UIImagePickerController()
imagePickVc.delegate = self
//3.弹出相册控制器
present(imagePickVc, animated: true, completion: nil)
}
2.实现相册的相关代理
extension QRCodeViewController:UIImagePickerControllerDelegate,UINavigationControllerDelegate
{
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{
//1.获取照片
guard let image = info[UIImagePickerControllerOriginalImage] as? UIImage else {
return
}
guard let ciIamge = CIImage(image: image) else {
return
}
//2.从相册中读取二维码
//2.1创建一个探测器(CIDetector是CoreImage框架中提供的一个识别类,包括对人脸、形状、条码、文本的识别)。
let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh])
//2.2利用探测器探测数据
guard let results = detector?.features(in: ciIamge) else {
return
}
//2.3取出探测器数据
for result in results {
NJLog(message: (result as! CIQRCodeFeature).messageString)
}
//3.如果实现代理方法系统不自动关闭相册
picker.dismiss(animated: true, completion: nil)
}
}
3.生成二维码
fun creteScancode
{
//1.创建滤镜
let filter = CIFilter(name: "CIQRCodeGenerator")
//2.还原滤镜默认属性
filter?.setDefaults()
//3设置需要生产二维码的数据到滤镜中
filter?.setValue("黄泽".data(using: .utf8), forKey: "inputMessage")
//4.从滤镜中取生产好的图片
guard let ciImage = filter?.outputImage
else {
return
}
let QRCodeImage = createNonInterpolatedUIImageFormCIImage(image: ciImage, size: 300)
let bgIcon = UIImage(named: "tabbar_compose_lbs")
customImageVIew.image = creatImage(bgImage: QRCodeImage, iconImage: bgIcon!)
}
//MARK: - 根据CIImage生成指定大小的高清UIImage
func createNonInterpolatedUIImageFormCIImage(image: CIImage, size: CGFloat) -> UIImage {
//CIImage没有frame与bounds属性,只有extent属性
let ciextent: CGRect = image.extent.integral
let scale: CGFloat = min(size/ciextent.width, size/ciextent.height)
let context = CIContext(options: nil) //创建基于GPU的CIContext对象,性能和效果更好
let bitmapImage: CGImage = context.createCGImage(image, from: ciextent)! //CIImage->CGImage
let width = ciextent.width * scale
let height = ciextent.height * scale
let cs: CGColorSpace = CGColorSpaceCreateDeviceGray() //灰度颜色通道
let info_UInt32 = CGImageAlphaInfo.none.rawValue
let bitmapRef = CGContext(data: nil, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: 0, space: cs, bitmapInfo: info_UInt32)! //图形上下文,画布
bitmapRef.interpolationQuality = CGInterpolationQuality.none //写入质量
bitmapRef.scaleBy(x: scale, y: scale) //调整“画布”的缩放
bitmapRef.draw(bitmapImage, in: ciextent) //绘制图片
let scaledImage: CGImage = bitmapRef.makeImage()! //保存
return UIImage(cgImage: scaledImage)
}
//MARK: - 根据背景图片和头像合成头像二维码
func creatImage(bgImage: UIImage, iconImage:UIImage) -> UIImage{
//开启图片上下文
UIGraphicsBeginImageContext(bgImage.size)
//绘制背景图片
bgImage.draw(in: CGRect(origin: CGPoint.zero, size: bgImage.size))
//绘制头像
let width: CGFloat = 50
let height: CGFloat = width
let x = (bgImage.size.width - width) * 0.5
let y = (bgImage.size.height - height) * 0.5
iconImage.draw(in: CGRect(x: x, y: y, width: width, height: height))
//取出绘制好的图片
let newImage = UIGraphicsGetImageFromCurrentImageContext()
//关闭上下文
UIGraphicsEndImageContext()
//返回合成好的图片
return newImage!
}