1??二維碼的掃描
??二維碼的掃描模塊,都會有個掃描的動畫,首先我們將動畫做出來,如何布局(創(chuàng)建了
DimensionViewController
和對應(yīng)的storyboard),對于實現(xiàn)重復(fù)掃描動畫很關(guān)鍵.首先我們在彈出掃描頁面放入一個view,約束固定大小以及垂直和水平的約束;接下來是在view放入二維碼掃描的邊框圖片qrcode_border
,按住command鍵選中view和邊框,設(shè)置他們上下左右的距離都為0;最后我們放上沖擊波的圖片wave
,設(shè)置它與view的約束關(guān)系為左,上右的距離為0,同時設(shè)置他們等高.接下來我們需要把?view的高度codeHeight
,wave的top的約束codeScanTop
, view的橫向約束viewCenterY
?拖線成為對應(yīng)的屬性.
private func startAnimate() {
//設(shè)置沖擊波底部和視圖底部對齊
codeScanTop.constant = -codeHeight.constant
view.layoutIfNeeded()
UIView.animateWithDuration(2.0) {
//設(shè)置動畫重復(fù)無數(shù)次
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()
//默認(rèn)值為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
}()
//預(yù)覽圖層
private lazy var previewLayer : AVCaptureVideoPreviewLayer = {
return AVCaptureVideoPreviewLayer(session :self.session)
}()
//專門用于描邊的圖層
private lazy var lineLayer : CALayer = CALayer()
//MARK:內(nèi)部控制方法,掃描二維碼
private func startCode(){
//判斷輸入能否添加到對話
if !session.canAddInput(input) {
DMLog("輸入沒有添加")
return
}
//判斷輸出能否添加到會話中
if !session.canAddOutput(output) {
DMLog("輸出沒有添加")
return
}
//添加輸入和輸出會話中
session.addInput(input)
session.addOutput(output)
//設(shè)置輸出能夠解析的數(shù)據(jù)類型
//設(shè)置數(shù)據(jù)類型一定要在輸出對象添加到會話之后才能設(shè)置
output.metadataObjectTypes = output.availableMetadataObjectTypes
//設(shè)置監(jiān)聽輸出解析到的數(shù)據(jù)
output.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
//添加預(yù)覽圖預(yù)覽圖層
view.layer.insertSublayer(previewLayer, atIndex: 0)
previewLayer.frame = view.bounds
//視圖上加載的是二維碼的描邊
view.layer.addSublayer(lineLayer)
lineLayer.frame = view.bounds
//開始掃描
session.startRunning()
}
接下來還需要執(zhí)行相對應(yīng)的代理方法,對掃描的消息進行相應(yīng)的處理,還有掃描到二維碼我們需要進行相應(yīng)的描邊,這樣可以定位到掃描的二維碼,即使當(dāng)你手機是成角度掃描的時候,依舊可以掃描出形狀(比如四邊形),這里用貝塞爾曲線畫圖
extension DimensionViewController:AVCaptureMetadataOutputObjectsDelegate{
func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!){
//只要掃描到就會調(diào)用
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 },是二維碼邊線的四個點
//轉(zhuǎn)換后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
}
//創(chuàng)建圖層,用于保存繪制的矩形
let layer = CAShapeLayer()
layer.lineWidth = 3
layer.strokeColor = UIColor.orangeColor().CGColor
layer.fillColor = UIColor.clearColor().CGColor //填充顏色
//創(chuàng)建UIBezierPat,繪制矩形,
//let path = UIBezierPath.init(rect: CGRect(x: 100,y: 100,width: 220,height: 220))
//貝塞爾曲線:將點移動到某一點;連接其他點,關(guān)閉路徑
var point : CGPoint = CGPointZero
var index = 0
//把數(shù)組字典中的xy轉(zhuǎn)化為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(){
//清除掃描二維碼出現(xiàn)多個圖層
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{
//實現(xiàn)該代理方法,選中一張圖片時系統(tǒng)不會自動關(guān)閉
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]){
guard let image = info["UIImagePickerControllerOriginalImage"] as? UIImage else{
return
}
let cimage = CIImage(image:image)
//創(chuàng)建一個探測器
let detector = CIDetector(ofType: CIDetectorTypeQRCode,context: nil,options: [CIDetectorAccuracy : CIDetectorAccuracyHigh]) //最后一個參數(shù)是掃描的精確度
let result = detector.featuresInImage(cimage!)
//去除探測的數(shù)據(jù)
for result in result{
let codeInfo = (result as! CIQRCodeFeature).messageString
//這里的message是一個table,顯示掃描到的信息的
message.text = codeInfo
}
picker.dismissViewControllerAnimated(true, completion: nil)
}
}
??制作二維碼哦,可以填入自己預(yù)設(shè)的消息,比如"小敏萌萌噠"??,這些代碼都是非常固定,需要的時候復(fù)制粘貼下就可以了哦.
class CreatQrCodeViewController: UIViewController {
@IBOutlet weak var qrCodeImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
//創(chuàng)建濾鏡
let filter = CIFilter(name: "CIQRCodeGenerator")
//還原默認(rèn)屬性
filter?.setDefaults()
//設(shè)置需要生成二維碼的數(shù)據(jù)到濾鏡中
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.創(chuàng)建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)
}
}
以上??