1⃣️二维码的扫描
🍓二维码的扫描模块,都会有个扫描的动画,首先我们将动画做出来,如何布局(创建了
DimensionViewController
和对应的storyboard),对于实现重复扫描动画很关键.首先我们在弹出扫描页面放入一个view,约束固定大小以及垂直和水平的约束;接下来是在view放入二维码扫描的边框图片qrcode_border
,按住command键选中view和边框,设置他们上下左右的距离都为0;最后我们放上冲击波的图片wave
,设置它与view的约束关系为左,上右的距离为0,同时设置他们等高.接下来我们需要把✨view的高度codeHeight
,wave的top的约束codeScanTop
, view的横向约束viewCenterY
✨拖线成为对应的属性.
private func startAnimate() {
//设置冲击波底部和视图底部对齐
codeScanTop.constant = -codeHeight.constant
view.layoutIfNeeded()
UIView.animateWithDuration(2.0) {
//设置动画重复无数次
UIView.setAnimationRepeatCount(MAXFLOAT)
self.codeScanTop.constant = self.codeHeight.constant
self.view.layoutIfNeeded()
}
}
🍓识别扫描的二维码,代码某些部分相对固定,不需要死记硬背哦,需要的童鞋也可以改成OC代码使用嘞.
//MARK:懒加载
//输入对象
private lazy var input:AVCaptureDeviceInput = {
let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
return try! AVCaptureDeviceInput(device:device)
}()
//会话
private lazy var session: AVCaptureSession = AVCaptureSession()
//输出对象
private lazy var output: AVCaptureMetadataOutput = {
let output = AVCaptureMetadataOutput()
//默认值为CGRectMake(0, 0, 1, 1),这个是传入的比例,横屏的左上角作为原点
output.rectOfInterest = CGRectMake((0.5-(110-self.viewCenterY.constant/2)/self.view.bounds.size.height),(0.5-110/self.view.bounds.size.width), 260/self.view.bounds.size.height, 260/self.view.bounds.size.width)
return output
}()
//预览图层
private lazy var previewLayer : AVCaptureVideoPreviewLayer = {
return AVCaptureVideoPreviewLayer(session :self.session)
}()
//专门用于描边的图层
private lazy var lineLayer : CALayer = CALayer()
//MARK:内部控制方法,扫描二维码
private func startCode(){
//判断输入能否添加到对话
if !session.canAddInput(input) {
DMLog("输入没有添加")
return
}
//判断输出能否添加到会话中
if !session.canAddOutput(output) {
DMLog("输出没有添加")
return
}
//添加输入和输出会话中
session.addInput(input)
session.addOutput(output)
//设置输出能够解析的数据类型
//设置数据类型一定要在输出对象添加到会话之后才能设置
output.metadataObjectTypes = output.availableMetadataObjectTypes
//设置监听输出解析到的数据
output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
//添加预览图预览图层
view.layer.insertSublayer(previewLayer, atIndex: 0)
previewLayer.frame = view.bounds
//视图上加载的是二维码的描边
view.layer.addSublayer(lineLayer)
lineLayer.frame = view.bounds
//开始扫描
session.startRunning()
}
接下来还需要执行相对应的代理方法,对扫描的消息进行相应的处理,还有扫描到二维码我们需要进行相应的描边,这样可以定位到扫描的二维码,即使当你手机是成角度扫描的时候,依旧可以扫描出形状(比如四边形),这里用贝塞尔曲线画图
extension DimensionViewController:AVCaptureMetadataOutputObjectsDelegate{
func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!){
//只要扫描到就会调用
message.text = metadataObjects.last?.stringValue
//DMLog(metadataObjects.last?.stringValue)
//DMLog(metadataObjects.last)
//corners { 0.4,0.9 0.5,0.9 0.5,0.6 0.4,0.7 },是二维码边线的四个点
//转换后corners { 140.3,238.3 141.7,317.6 220.6,318.9 222.4,238.8 },
cleanLayers()
guard let meta = metadataObjects.last as? AVMetadataObject else{
DMLog("没有扫描到二维码")
return
}
let objc = previewLayer.transformedMetadataObjectForMetadataObject(meta)
guard let newObj = objc as? AVMetadataMachineReadableCodeObject else{
return
}
//DMLog(newObj)
//对扫描二维码进行描边
drawLine(newObj)
}
private func drawLine(objc : AVMetadataMachineReadableCodeObject){
//安全校验
guard let arr = objc.corners else{
return
}
//创建图层,用于保存绘制的矩形
let layer = CAShapeLayer()
layer.lineWidth = 3
layer.strokeColor = UIColor.orangeColor().CGColor
layer.fillColor = UIColor.clearColor().CGColor //填充颜色
//创建UIBezierPat,绘制矩形,
//let path = UIBezierPath.init(rect: CGRect(x: 100,y: 100,width: 220,height: 220))
//贝塞尔曲线:将点移动到某一点;连接其他点,关闭路径
var point : CGPoint = CGPointZero
var index = 0
//把数组字典中的xy转化为CGPoint
CGPointMakeWithDictionaryRepresentation(arr[index++] as! CFDictionary, &point)
let path = UIBezierPath()
path.moveToPoint(point)
//连接
while index < arr.count { CGPointMakeWithDictionaryRepresentation(arr[index++] as! CFDictionary, &point)
path.addLineToPoint(point)
}
path.closePath()
layer.path = path.CGPath
lineLayer.addSublayer(layer)
}
private func cleanLayers(){
//清除扫描二维码出现多个图层
guard let subLayers = lineLayer.sublayers else{
return
}
for layer in subLayers {
layer.removeFromSuperlayer()
}
}
}
🍓接下来就到了识别相册中的二维码了,请看以下代码
//从相册中识别二维码
if !UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.PhotoLibrary) {
return
}
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
presentViewController(imagePicker, animated: true, completion: nil)
extension DimensionViewController : UIImagePickerControllerDelegate,UINavigationControllerDelegate{
//实现该代理方法,选中一张图片时系统不会自动关闭
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]){
guard let image = info["UIImagePickerControllerOriginalImage"] as? UIImage else{
return
}
let cimage = CIImage(image:image)
//创建一个探测器
let detector = CIDetector(ofType: CIDetectorTypeQRCode,context: nil,options: [CIDetectorAccuracy : CIDetectorAccuracyHigh]) //最后一个参数是扫描的精确度
let result = detector.featuresInImage(cimage!)
//去除探测的数据
for result in result{
let codeInfo = (result as! CIQRCodeFeature).messageString
//这里的message是一个table,显示扫描到的信息的
message.text = codeInfo
}
picker.dismissViewControllerAnimated(true, completion: nil)
}
}
🍓制作二维码哦,可以填入自己预设的消息,比如"小敏萌萌哒"😄,这些代码都是非常固定,需要的时候复制粘贴下就可以了哦.
class CreatQrCodeViewController: UIViewController {
@IBOutlet weak var qrCodeImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
//创建滤镜
let filter = CIFilter(name: "CIQRCodeGenerator")
//还原默认属性
filter?.setDefaults()
//设置需要生成二维码的数据到滤镜中
filter?.setValue("小敏萌萌哒".dataUsingEncoding(NSUTF8StringEncoding), forKeyPath: "InputMessage")
//从滤镜中取出生成好的二维码
guard let ciImage = filter?.outputImage else{
DMLog("没有二维码")
return
}
qrCodeImage.image = createNonInterpolatedUIImageFormCIImage(ciImage, size: 220)
}
/**
生成高清二维码
- parameter image: 需要生成原始图片
- parameter size: 生成的二维码的宽高
*/
private func createNonInterpolatedUIImageFormCIImage(image: CIImage, size: CGFloat) -> UIImage {
let extent: CGRect = CGRectIntegral(image.extent)
let scale: CGFloat = min(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent))
// 1.创建bitmap;
let width = CGRectGetWidth(extent) * scale
let height = CGRectGetHeight(extent) * scale
let cs: CGColorSpaceRef = CGColorSpaceCreateDeviceGray()!
let bitmapRef = CGBitmapContextCreate(nil, Int(width), Int(height), 8, 0, cs, 0)!
let context = CIContext(options: nil)
let bitmapImage: CGImageRef = context.createCGImage(image, fromRect: extent)
CGContextSetInterpolationQuality(bitmapRef, CGInterpolationQuality.None)
CGContextScaleCTM(bitmapRef, scale, scale);
CGContextDrawImage(bitmapRef, extent, bitmapImage);
// 2.保存bitmap到图片
let scaledImage: CGImageRef = CGBitmapContextCreateImage(bitmapRef)!
return UIImage(CGImage: scaledImage)
}
}
以上😄