标签:
特定的几何图形
按一定规律在平面分布的黑白相间的图形记录数据符号信息的安全提示 —— 不要见码就扫
更多内容请参阅:http://baike.baidu.com/view/132241.htm
QRCodeViewController.swift
& QRCode.storyboard
Storyboard
中添加 UIViewController
并且指定子类HomeTableViewController
中增加 scanQRCode
函数,显示 QRCode
控制器@IBAction func scanQRCode() {
presentViewController(UIStoryboard.initViewController("QRCode"), animated: true, completion: nil)
}
Navigation Bar
的 Style 设置为 Black
增加 UITabBar
二维码扫描
和 条形码扫描
两种方式在 AppDelegate
中增加设置外观函数
/// 设置外观(一经设置,全局有效,外观设置要尽量的早)
private func setupAppearance() {
UINavigationBar.appearance().tintColor = UIColor.orangeColor()
UITabBar.appearance().tintColor = UIColor.orangeColor()
}
在屏幕中心添加扫描视图
在扫描视图内部添加边框图像视图
,边框图片切片如下
Style
修改为 Black
@IBOutlet weak var tabBar: UITabBar!
override func viewDidLoad() {
super.viewDidLoad()
tabBar.selectedItem = tabBar.items![0] as? UITabBarItem
}
func tabBar(tabBar: UITabBar, didSelectItem item: UITabBarItem!) {
heightConstraint.constant = weightConstraint.constant * (item.tag == 1 ? 0.5 : 1)
}
扫描视图
的参照override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
scanAnimation()
}
/// 冲击波动画
func scanAnimation() {
// 停止图层动画
scanImage.layer.removeAllAnimations()
// 设定动画初始约束
self.topScanConstraint.constant = -heightConstraint.constant
// 更新视图布局
self.view.layoutIfNeeded()
// 开始动画
UIView.animateWithDuration(2.0, animations: { () -> Void in
self.topScanConstraint.constant = self.heightConstraint.constant
UIView.setAnimationRepeatCount(MAXFLOAT)
self.view.layoutIfNeeded()
})
}
// MARK: - UITabBarDelegate
func tabBar(tabBar: UITabBar, didSelectItem item: UITabBarItem!) {
heightConstraint.constant = weightConstraint.constant * (item.tag == 1 ? 0.5 : 1)
scanAnimation()
}
注意:动画函数的前三句话非常重要!
Clip Subviews
属性冲击波
初始 Top
约束数值 -300ZXing
Android使用多ZBar
iOS使用多
提示:以上两个框架都是老牌二维码框架,不过都不支持 64 位
AVFoundation
框架,但是不支持图片识别功能AVFoundation
只支持通过摄像头扫描识别/// 拍摄会话,是扫描的桥梁
lazy var session: AVCaptureSession = {
return AVCaptureSession()
}()
/// 摄像头输入
lazy var videoInput: AVCaptureDeviceInput? = {
// 获取摄像头设备
if let device = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo) {
return AVCaptureDeviceInput(device: device, error: nil)
}
return nil
}()
/// 数据输出
lazy var dataOutput: AVCaptureMetadataOutput = {
return AVCaptureMetadataOutput()
}()
func scan() {
// 1. 添加输入设备
if !session.canAddInput(videoInput) {
print("无法添加输入设备")
return
}
session.addInput(videoInput)
// 2. 添加输出设备
if !session.canAddOutput(dataOutput) {
println("无法添加输出设备")
return
}
session.addOutput(dataOutput)
println(dataOutput.availableMetadataObjectTypes)
}
注意,一定要把输出设备添加到会话后,才有可用数据类型
// 2.1 设置扫描数据类型(全部支持)
dataOutput.metadataObjectTypes = dataOutput.availableMetadataObjectTypes
// 2.2 设置输出代理
dataOutput.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
// 3. 启动会话
session.startRunning()
// MARK: - AVCaptureMetadataOutputObjectsDelegate
func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
println(metadataObjects)
}
必须要启动会话,才能开始扫描
/// 预览图层
lazy var previewLayer: AVCaptureVideoPreviewLayer = {
let layer = AVCaptureVideoPreviewLayer(session: self.session)
layer.frame = self.view.bounds
return layer
}()
进一步体会一下此处的
self.
self.
在 OC
中使用 self.
能够调用属性的 getter
方法,确保对象一定能够拿到
完整的扫描函数代码
/// 扫描函数
func scan() {
// 1. 添加输入设备
if !session.canAddInput(videoInput) {
print("无法添加输入设备")
return
}
session.addInput(videoInput)
// 2. 添加输出设备
if !session.canAddOutput(dataOutput) {
println("无法添加输出设备")
return
}
session.addOutput(dataOutput)
println(dataOutput.availableMetadataObjectTypes)
// 2.1 设置扫描数据类型(全部支持)
dataOutput.metadataObjectTypes = dataOutput.availableMetadataObjectTypes
// 2.2 设置输出代理
dataOutput.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
// 3. 添加预览图层
view.layer.insertSublayer(previewLayer, atIndex: 0)
// 4. 启动会话
session.startRunning()
}
func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
for dataObject in metadataObjects {
println(dataObject)
}
}
lazy var drawLayer: CALayer = {
let layer = CALayer()
layer.frame = self.view.bounds
return layer
}()
// 3. 添加图层
view.layer.insertSublayer(drawLayer, atIndex: 0)
view.layer.insertSublayer(previewLayer, atIndex: 0)
// 4. 启动会话
session.startRunning()
注意:一定要用
insertSublayer
,否则会遮挡住TabBar
for dataObject in metadataObjects as! [AVMetadataMachineReadableCodeObject] {
println(dataObject)
let obj = previewLayer.transformedMetadataObjectForMetadataObject(dataObject)
println(obj)
}
# 转换前
<AVMetadataMachineReadableCodeObject: 0x170220720,
type="org.iso.QRCode",
bounds={ 0.4,0.4 0.1x0.2 }>
corners { 0.4,0.6 0.5,0.6 0.5,0.4 0.4,0.4 },
time 155921691680958,
stringValue "http://weibo.cn/qr/userinfo?uid=5365823342"
# 转换后
<AVMetadataMachineReadableCodeObject: 0x170622cc0,
type="org.iso.QRCode",
bounds={ 116.6,224.9 79.5x80.0 }>
corners { 116.6,226.1 117.2,304.4 196.1,304.9 195.7,224.9 },
time 155921691680958,
stringValue "http://weibo.cn/qr/userinfo?uid=5365823342"
转换的目的是将采集到的坐标转换成能够识别的坐标数值
/// 创建路径
///
/// :param: points The value of this property is an array of CFDictionary objects
///
/// :returns: 贝赛尔路径
private func createPath(points: NSArray)-> UIBezierPath {
let path = UIBezierPath()
var point = CGPoint()
var index = 0
// 起始点
CGPointMakeWithDictionaryRepresentation(points[index++] as! CFDictionaryRef, &point)
path.moveToPoint(point)
// 遍历剩余的点
while index < points.count {
CGPointMakeWithDictionaryRepresentation(points[index++] as! CFDictionaryRef, &point)
path.addLineToPoint(point)
}
// 关闭路径
path.closePath()
return path
}
注意
corners
是保存CFDictionary
对象的数组
/// 绘制编码变线
private func drawCodeCorners(codeObject: AVMetadataMachineReadableCodeObject) {
if codeObject.corners.count == 0 {
return
}
// 建立形状图层
let shapeLayer = CAShapeLayer()
shapeLayer.strokeColor = UIColor.greenColor().CGColor
shapeLayer.fillColor = UIColor.clearColor().CGColor
shapeLayer.lineWidth = 4
shapeLayer.path = createPath(codeObject.corners).CGPath
// 添加形状图层
drawLayer.addSublayer(shapeLayer)
}
注意:一定要判断
corners
是否包含数据,否则会崩溃
/// 清空绘图图层
private func clearDrawLayer() {
if drawLayer.sublayers != nil {
for l in drawLayer.sublayers {
l.removeFromSuperlayer()
}
}
}
注意:一定要判断
subLayers
否则会崩溃
func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
clearDrawLayer()
for dataObject in metadataObjects as! [AVMetadataMachineReadableCodeObject] {
// 转换编码对象
let codeObject = previewLayer.transformedMetadataObjectForMetadataObject(dataObject) as! AVMetadataMachineReadableCodeObject
drawCodeCorners(codeObject)
println(codeObject)
}
}
/// 生成二维码
public func generateImage(stringValue: String, avatarImage: UIImage?, avatarScale: CGFloat = 0.25, color: CIColor = CIColor(red: 0, green: 0, blue: 0), backColor: CIColor = CIColor(red: 1, green: 1, blue: 1)) -> UIImage? {
let qrFilter = CIFilter(name: "CIQRCodeGenerator")
qrFilter.setDefaults()
qrFilter.setValue(stringValue.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false), forKey: "inputMessage")
let ciImage = qrFilter.outputImage
let colorFilter = CIFilter(name: "CIFalseColor")
colorFilter.setDefaults()
colorFilter.setValue(ciImage, forKey: "inputImage")
colorFilter.setValue(color, forKey: "inputColor0")
colorFilter.setValue(backColor, forKey: "inputColor1")
let transform = CGAffineTransformMakeScale(5, 5)
let transformedImage = colorFilter.outputImage.imageByApplyingTransform(transform)
let image = UIImage(CIImage: transformedImage)
if avatarImage != nil && image != nil {
return insertAvatarImage(image!, avatarImage: avatarImage!, scale: avatarScale)
}
return image
}
func insertAvatarImage(codeImage: UIImage, avatarImage: UIImage, scale: CGFloat) -> UIImage {
let rect = CGRectMake(0, 0, codeImage.size.width, codeImage.size.height)
UIGraphicsBeginImageContext(rect.size)
codeImage.drawInRect(rect)
let avatarSize = CGSizeMake(rect.size.width * scale, rect.size.height * scale)
let x = (rect.width - avatarSize.width) * 0.5
let y = (rect.height - avatarSize.height) * 0.5
avatarImage.drawInRect(CGRectMake(x, y, avatarSize.width, avatarSize.height))
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return result
}
标签:
原文地址:http://www.cnblogs.com/Milo-CTO/p/4771200.html