|
|
@@ -9,19 +9,19 @@
|
|
|
import UIKit
|
|
|
import AVFoundation
|
|
|
|
|
|
-public struct LBXScanResult {
|
|
|
-
|
|
|
+public struct LBXScanResult {
|
|
|
+
|
|
|
//码内容
|
|
|
- public var strScanned:String? = ""
|
|
|
+ public var strScanned: String? = ""
|
|
|
//扫描图像
|
|
|
- public var imgScanned:UIImage?
|
|
|
+ public var imgScanned: UIImage?
|
|
|
//码的类型
|
|
|
- public var strBarCodeType:String? = ""
|
|
|
-
|
|
|
+ public var strBarCodeType: String? = ""
|
|
|
+
|
|
|
//码在图像中的位置
|
|
|
- public var arrayCorner:[AnyObject]?
|
|
|
-
|
|
|
- public init(str:String?,img:UIImage?,barCodeType:String?,corner:[AnyObject]?)
|
|
|
+ public var arrayCorner: [AnyObject]?
|
|
|
+
|
|
|
+ public init(str: String?, img: UIImage?, barCodeType: String?, corner: [AnyObject]?)
|
|
|
{
|
|
|
self.strScanned = str
|
|
|
self.imgScanned = img
|
|
|
@@ -32,28 +32,34 @@ public struct LBXScanResult {
|
|
|
|
|
|
|
|
|
|
|
|
-open class LBXScanWrapper: NSObject,AVCaptureMetadataOutputObjectsDelegate {
|
|
|
-
|
|
|
+open class LBXScanWrapper: NSObject, AVCaptureMetadataOutputObjectsDelegate {
|
|
|
+
|
|
|
let device = AVCaptureDevice.default(for: AVMediaType.video)
|
|
|
- var input:AVCaptureDeviceInput?
|
|
|
- var output:AVCaptureMetadataOutput
|
|
|
-
|
|
|
+ var input: AVCaptureDeviceInput?
|
|
|
+ var output: AVCaptureMetadataOutput
|
|
|
+
|
|
|
let session = AVCaptureSession()
|
|
|
- var previewLayer:AVCaptureVideoPreviewLayer?
|
|
|
- var stillImageOutput:AVCaptureStillImageOutput?
|
|
|
+ var previewLayer: AVCaptureVideoPreviewLayer?
|
|
|
+ var stillImageOutput: AVCaptureStillImageOutput?
|
|
|
+
|
|
|
+ var videoPreView: UIView?
|
|
|
|
|
|
- //存储返回结果
|
|
|
- var arrayResult:[LBXScanResult] = [];
|
|
|
+ var scaleSize:CGFloat = 1
|
|
|
|
|
|
+ //存储返回结果
|
|
|
+ var arrayResult: [LBXScanResult] = [];
|
|
|
+
|
|
|
//扫码结果返回block
|
|
|
- var successBlock:([LBXScanResult]) -> Void
|
|
|
-
|
|
|
+ var successBlock: ([LBXScanResult]) -> Void
|
|
|
+
|
|
|
//是否需要拍照
|
|
|
- var isNeedCaptureImage:Bool
|
|
|
-
|
|
|
+ var isNeedCaptureImage: Bool
|
|
|
+
|
|
|
//当前扫码结果是否处理
|
|
|
- var isNeedScanResult:Bool = true
|
|
|
+ var isNeedScanResult: Bool = true
|
|
|
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
初始化设备
|
|
|
- parameter videoPreView: 视频显示UIView
|
|
|
@@ -63,90 +69,92 @@ open class LBXScanWrapper: NSObject,AVCaptureMetadataOutputObjectsDelegate {
|
|
|
- parameter success: 返回识别信息
|
|
|
- returns:
|
|
|
*/
|
|
|
- init( videoPreView:UIView,objType:[AVMetadataObject.ObjectType] = [(AVMetadataObject.ObjectType.qr as NSString) as AVMetadataObject.ObjectType],isCaptureImg:Bool,cropRect:CGRect=CGRect.zero,success:@escaping ( ([LBXScanResult]) -> Void) )
|
|
|
+ init(videoPreView: UIView, objType: [AVMetadataObject.ObjectType] = [(AVMetadataObject.ObjectType.qr as NSString) as AVMetadataObject.ObjectType], isCaptureImg: Bool, cropRect: CGRect = CGRect.zero, success: @escaping (([LBXScanResult]) -> Void))
|
|
|
{
|
|
|
- do{
|
|
|
+ self.videoPreView = videoPreView
|
|
|
+
|
|
|
+ do {
|
|
|
input = try AVCaptureDeviceInput(device: device!)
|
|
|
}
|
|
|
catch let error as NSError {
|
|
|
print("AVCaptureDeviceInput(): \(error)")
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
successBlock = success
|
|
|
-
|
|
|
+
|
|
|
// Output
|
|
|
output = AVCaptureMetadataOutput()
|
|
|
-
|
|
|
+
|
|
|
isNeedCaptureImage = isCaptureImg
|
|
|
-
|
|
|
+
|
|
|
stillImageOutput = AVCaptureStillImageOutput();
|
|
|
-
|
|
|
+
|
|
|
super.init()
|
|
|
-
|
|
|
+
|
|
|
if device == nil || input == nil {
|
|
|
return
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if session.canAddInput(input!) {
|
|
|
session.addInput(input!)
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if session.canAddOutput(output) {
|
|
|
session.addOutput(output)
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if session.canAddOutput(stillImageOutput!) {
|
|
|
session.addOutput(stillImageOutput!)
|
|
|
}
|
|
|
-
|
|
|
- let outputSettings:Dictionary = [AVVideoCodecJPEG:AVVideoCodecKey]
|
|
|
+
|
|
|
+ let outputSettings: Dictionary = [AVVideoCodecJPEG: AVVideoCodecKey]
|
|
|
stillImageOutput?.outputSettings = outputSettings
|
|
|
-
|
|
|
+
|
|
|
session.sessionPreset = AVCaptureSession.Preset.high
|
|
|
-
|
|
|
+
|
|
|
//参数设置
|
|
|
output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
|
|
|
-
|
|
|
+
|
|
|
output.metadataObjectTypes = objType
|
|
|
-
|
|
|
- // output.metadataObjectTypes = [AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode128Code]
|
|
|
-
|
|
|
+
|
|
|
if !cropRect.equalTo(CGRect.zero)
|
|
|
{
|
|
|
//启动相机后,直接修改该参数无效
|
|
|
output.rectOfInterest = cropRect
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
previewLayer = AVCaptureVideoPreviewLayer(session: session)
|
|
|
previewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
|
|
|
-
|
|
|
- var frame:CGRect = videoPreView.frame
|
|
|
+
|
|
|
+ var frame: CGRect = videoPreView.frame
|
|
|
frame.origin = CGPoint.zero
|
|
|
previewLayer?.frame = frame
|
|
|
+
|
|
|
+ videoPreView.layer.insertSublayer(previewLayer!, at: 0)
|
|
|
|
|
|
- videoPreView.layer .insertSublayer(previewLayer!, at: 0)
|
|
|
-
|
|
|
- if ( device!.isFocusPointOfInterestSupported && device!.isFocusModeSupported(AVCaptureDevice.FocusMode.continuousAutoFocus) )
|
|
|
- {
|
|
|
- do
|
|
|
+ do {
|
|
|
+ try input?.device.lockForConfiguration()
|
|
|
+
|
|
|
+ if device?.isWhiteBalanceModeSupported(.autoWhiteBalance) == true {
|
|
|
+ input?.device.whiteBalanceMode = .autoWhiteBalance
|
|
|
+ }
|
|
|
+
|
|
|
+ if (device!.isFocusPointOfInterestSupported && device!.isFocusModeSupported(AVCaptureDevice.FocusMode.continuousAutoFocus))
|
|
|
{
|
|
|
- try input?.device.lockForConfiguration()
|
|
|
-
|
|
|
input?.device.focusMode = AVCaptureDevice.FocusMode.continuousAutoFocus
|
|
|
-
|
|
|
- input?.device.unlockForConfiguration()
|
|
|
- }
|
|
|
- catch let error as NSError {
|
|
|
- print("device.lockForConfiguration(): \(error)")
|
|
|
-
|
|
|
}
|
|
|
+
|
|
|
+ input?.device.unlockForConfiguration()
|
|
|
+ } catch let error as NSError {
|
|
|
+ print("device.lockForConfiguration(): \(error)")
|
|
|
}
|
|
|
+
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
public func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
|
|
|
captureOutput(output, didOutputMetadataObjects: metadataObjects, from: connection)
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
func start()
|
|
|
{
|
|
|
if !session.isRunning
|
|
|
@@ -164,39 +172,92 @@ open class LBXScanWrapper: NSObject,AVCaptureMetadataOutputObjectsDelegate {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- open func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
|
|
|
-
|
|
|
+// func setVideoScale(scale: CGFloat) {
|
|
|
+// print("调整镜头................")
|
|
|
+// do {
|
|
|
+// try input?.device.lockForConfiguration()
|
|
|
+// let videoConnection = self.connectionWithMediaType(mediaType: .video, connections: self.stillImageOutput?.connections ?? [])
|
|
|
+// let maxScaleAndCropFactor = self.stillImageOutput?.connection(with: .video)?.videoMaxScaleAndCropFactor ?? 0 / 16
|
|
|
+// var newScale = scale
|
|
|
+// if newScale > maxScaleAndCropFactor {
|
|
|
+// newScale = maxScaleAndCropFactor
|
|
|
+// }
|
|
|
+// print("scale.....\(newScale)")
|
|
|
+// let videoFactor = videoConnection?.videoScaleAndCropFactor ?? 1
|
|
|
+// let zoom = newScale / videoFactor
|
|
|
+// videoConnection?.videoScaleAndCropFactor = newScale
|
|
|
+// input?.device.unlockForConfiguration()
|
|
|
+// print("zoom.......\(zoom)")
|
|
|
+// if let transform = self.videoPreView?.transform {
|
|
|
+// self.videoPreView?.transform = transform.scaledBy(x: zoom, y: zoom)
|
|
|
+// }
|
|
|
+//
|
|
|
+// } catch let error as NSError {
|
|
|
+// print("device.lockForConfiguration(): \(error)")
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// func changeVideoScale(obj: AVMetadataMachineReadableCodeObject?) {
|
|
|
+// if let o = obj {
|
|
|
+// let arr = o.corners
|
|
|
+// if arr.count >= 3 {
|
|
|
+// let point = arr[1]
|
|
|
+// let point2 = arr[2]
|
|
|
+// let scale = 150 / (point2.x - point.x) //当二维码图片宽小于150,进行放大
|
|
|
+// print("scale.......\(scale)")
|
|
|
+// if scale > 1 {
|
|
|
+// for item in stride(from: 1, to: scale, by: 0.01) {
|
|
|
+// self.setVideoScale(scale: item)
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+ open func captureOutput(_ captureOutput: AVCaptureOutput, didOutputMetadataObjects metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
|
|
|
+
|
|
|
if !isNeedScanResult
|
|
|
{
|
|
|
//上一帧处理中
|
|
|
return
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
isNeedScanResult = false
|
|
|
-
|
|
|
+
|
|
|
arrayResult.removeAll()
|
|
|
+
|
|
|
+// print(metadataObjects)
|
|
|
+
|
|
|
+// if metadataObjects.count < 1 {
|
|
|
+// if self.scaleSize == 1 {
|
|
|
+// self.scaleSize = 2
|
|
|
+// }else {
|
|
|
+// self.scaleSize = 1
|
|
|
+// }
|
|
|
+// self.setVideoScale(scale: self.scaleSize)
|
|
|
+// }
|
|
|
|
|
|
//识别扫码类型
|
|
|
- for current:Any in metadataObjects
|
|
|
+ for current in metadataObjects
|
|
|
{
|
|
|
- if (current as AnyObject).isKind(of: AVMetadataMachineReadableCodeObject.self)
|
|
|
+ if (current).isKind(of: AVMetadataMachineReadableCodeObject.self)
|
|
|
{
|
|
|
let code = current as! AVMetadataMachineReadableCodeObject
|
|
|
-
|
|
|
+
|
|
|
//码类型
|
|
|
let codeType = code.type
|
|
|
// print("code type:%@",codeType)
|
|
|
//码内容
|
|
|
let codeContent = code.stringValue
|
|
|
// print("code string:%@",codeContent)
|
|
|
-
|
|
|
+
|
|
|
//4个字典,分别 左上角-右上角-右下角-左下角的 坐标百分百,可以使用这个比例抠出码的图像
|
|
|
// let arrayRatio = code.corners
|
|
|
-
|
|
|
+
|
|
|
arrayResult.append(LBXScanResult(str: codeContent, img: UIImage(), barCodeType: codeType.rawValue, corner: code.corners as [AnyObject]?))
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
if arrayResult.count > 0
|
|
|
{
|
|
|
if isNeedCaptureImage
|
|
|
@@ -208,52 +269,52 @@ open class LBXScanWrapper: NSObject,AVCaptureMetadataOutputObjectsDelegate {
|
|
|
stop()
|
|
|
successBlock(arrayResult)
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
isNeedScanResult = true
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
//MARK: ----拍照
|
|
|
open func captureImage()
|
|
|
{
|
|
|
- let stillImageConnection:AVCaptureConnection? = connectionWithMediaType(mediaType: AVMediaType.video as AVMediaType, connections: (stillImageOutput?.connections)! as [AnyObject])
|
|
|
-
|
|
|
-
|
|
|
+ let stillImageConnection: AVCaptureConnection? = connectionWithMediaType(mediaType: AVMediaType.video as AVMediaType, connections: (stillImageOutput?.connections)! as [AnyObject])
|
|
|
+
|
|
|
+
|
|
|
stillImageOutput?.captureStillImageAsynchronously(from: stillImageConnection!, completionHandler: { (imageDataSampleBuffer, error) -> Void in
|
|
|
-
|
|
|
+
|
|
|
self.stop()
|
|
|
if imageDataSampleBuffer != nil
|
|
|
{
|
|
|
let imageData: Data = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer!)!
|
|
|
- let scanImg:UIImage? = UIImage(data: imageData)
|
|
|
-
|
|
|
-
|
|
|
- for idx in 0...self.arrayResult.count-1
|
|
|
+ let scanImg: UIImage? = UIImage(data: imageData)
|
|
|
+
|
|
|
+
|
|
|
+ for idx in 0...self.arrayResult.count - 1
|
|
|
{
|
|
|
self.arrayResult[idx].imgScanned = scanImg
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
self.successBlock(self.arrayResult)
|
|
|
-
|
|
|
+
|
|
|
})
|
|
|
}
|
|
|
-
|
|
|
- open func connectionWithMediaType(mediaType:AVMediaType, connections:[AnyObject]) -> AVCaptureConnection?
|
|
|
+
|
|
|
+ open func connectionWithMediaType(mediaType: AVMediaType, connections: [AnyObject]) -> AVCaptureConnection?
|
|
|
{
|
|
|
- for connection:AnyObject in connections
|
|
|
+ for connection: AnyObject in connections
|
|
|
{
|
|
|
- let connectionTmp:AVCaptureConnection = connection as! AVCaptureConnection
|
|
|
-
|
|
|
- for port:Any in connectionTmp.inputPorts
|
|
|
+ let connectionTmp: AVCaptureConnection = connection as! AVCaptureConnection
|
|
|
+
|
|
|
+ for port: Any in connectionTmp.inputPorts
|
|
|
{
|
|
|
if (port as AnyObject).isKind(of: AVCaptureInput.Port.self)
|
|
|
{
|
|
|
- let portTmp:AVCaptureInput.Port = port as! AVCaptureInput.Port
|
|
|
+ let portTmp: AVCaptureInput.Port = port as! AVCaptureInput.Port
|
|
|
if portTmp.mediaType == mediaType
|
|
|
{
|
|
|
return connectionTmp
|
|
|
@@ -263,58 +324,58 @@ open class LBXScanWrapper: NSObject,AVCaptureMetadataOutputObjectsDelegate {
|
|
|
}
|
|
|
return nil
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
//MARK:切换识别区域
|
|
|
- open func changeScanRect(cropRect:CGRect)
|
|
|
+ open func changeScanRect(cropRect: CGRect)
|
|
|
{
|
|
|
//待测试,不知道是否有效
|
|
|
stop()
|
|
|
output.rectOfInterest = cropRect
|
|
|
start()
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
//MARK: 切换识别码的类型
|
|
|
- open func changeScanType(objType:[AVMetadataObject.ObjectType])
|
|
|
+ open func changeScanType(objType: [AVMetadataObject.ObjectType])
|
|
|
{
|
|
|
//待测试中途修改是否有效
|
|
|
output.metadataObjectTypes = objType
|
|
|
}
|
|
|
-
|
|
|
- open func isGetFlash()->Bool
|
|
|
+
|
|
|
+ open func isGetFlash() -> Bool
|
|
|
{
|
|
|
- if (device != nil && device!.hasFlash && device!.hasTorch)
|
|
|
+ if (device != nil && device!.hasFlash && device!.hasTorch)
|
|
|
{
|
|
|
return true
|
|
|
}
|
|
|
return false
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
打开或关闭闪关灯
|
|
|
- parameter torch: true:打开闪关灯 false:关闭闪光灯
|
|
|
*/
|
|
|
- open func setTorch(torch:Bool)
|
|
|
+ open func setTorch(torch: Bool)
|
|
|
{
|
|
|
if isGetFlash()
|
|
|
{
|
|
|
do
|
|
|
{
|
|
|
try input?.device.lockForConfiguration()
|
|
|
-
|
|
|
+
|
|
|
input?.device.torchMode = torch ? AVCaptureDevice.TorchMode.on : AVCaptureDevice.TorchMode.off
|
|
|
-
|
|
|
+
|
|
|
input?.device.unlockForConfiguration()
|
|
|
}
|
|
|
catch let error as NSError {
|
|
|
print("device.lockForConfiguration(): \(error)")
|
|
|
-
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
/**
|
|
|
------闪光灯打开或关闭
|
|
|
*/
|
|
|
@@ -325,9 +386,9 @@ open class LBXScanWrapper: NSObject,AVCaptureMetadataOutputObjectsDelegate {
|
|
|
do
|
|
|
{
|
|
|
try input?.device.lockForConfiguration()
|
|
|
-
|
|
|
+
|
|
|
var torch = false
|
|
|
-
|
|
|
+
|
|
|
if input?.device.torchMode == AVCaptureDevice.TorchMode.on
|
|
|
{
|
|
|
torch = false
|
|
|
@@ -336,52 +397,52 @@ open class LBXScanWrapper: NSObject,AVCaptureMetadataOutputObjectsDelegate {
|
|
|
{
|
|
|
torch = true
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
input?.device.torchMode = torch ? AVCaptureDevice.TorchMode.on : AVCaptureDevice.TorchMode.off
|
|
|
-
|
|
|
+
|
|
|
input?.device.unlockForConfiguration()
|
|
|
}
|
|
|
catch let error as NSError {
|
|
|
print("device.lockForConfiguration(): \(error)")
|
|
|
-
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
//MARK: ------获取系统默认支持的码的类型
|
|
|
- static func defaultMetaDataObjectTypes() ->[AVMetadataObject.ObjectType]
|
|
|
+ static func defaultMetaDataObjectTypes() -> [AVMetadataObject.ObjectType]
|
|
|
{
|
|
|
var types =
|
|
|
[AVMetadataObject.ObjectType.qr,
|
|
|
- AVMetadataObject.ObjectType.upce,
|
|
|
- AVMetadataObject.ObjectType.code39,
|
|
|
- AVMetadataObject.ObjectType.code39Mod43,
|
|
|
- AVMetadataObject.ObjectType.ean13,
|
|
|
- AVMetadataObject.ObjectType.ean8,
|
|
|
- AVMetadataObject.ObjectType.code93,
|
|
|
- AVMetadataObject.ObjectType.code128,
|
|
|
- AVMetadataObject.ObjectType.pdf417,
|
|
|
- AVMetadataObject.ObjectType.aztec
|
|
|
- ]
|
|
|
+ AVMetadataObject.ObjectType.upce,
|
|
|
+ AVMetadataObject.ObjectType.code39,
|
|
|
+ AVMetadataObject.ObjectType.code39Mod43,
|
|
|
+ AVMetadataObject.ObjectType.ean13,
|
|
|
+ AVMetadataObject.ObjectType.ean8,
|
|
|
+ AVMetadataObject.ObjectType.code93,
|
|
|
+ AVMetadataObject.ObjectType.code128,
|
|
|
+ AVMetadataObject.ObjectType.pdf417,
|
|
|
+ AVMetadataObject.ObjectType.aztec
|
|
|
+ ]
|
|
|
//if #available(iOS 8.0, *)
|
|
|
-
|
|
|
+
|
|
|
types.append(AVMetadataObject.ObjectType.interleaved2of5)
|
|
|
types.append(AVMetadataObject.ObjectType.itf14)
|
|
|
types.append(AVMetadataObject.ObjectType.dataMatrix)
|
|
|
return types as [AVMetadataObject.ObjectType]
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
- static func isSysIos8Later()->Bool
|
|
|
+
|
|
|
+
|
|
|
+ static func isSysIos8Later() -> Bool
|
|
|
{
|
|
|
// return floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_8_0
|
|
|
-
|
|
|
+
|
|
|
if #available(iOS 8, *) {
|
|
|
return true;
|
|
|
}
|
|
|
return false
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
识别二维码码图像
|
|
|
|
|
|
@@ -389,74 +450,74 @@ open class LBXScanWrapper: NSObject,AVCaptureMetadataOutputObjectsDelegate {
|
|
|
|
|
|
- returns: 返回识别结果
|
|
|
*/
|
|
|
- static public func recognizeQRImage(image:UIImage) ->[LBXScanResult]
|
|
|
+ static public func recognizeQRImage(image: UIImage) -> [LBXScanResult]
|
|
|
{
|
|
|
- var returnResult:[LBXScanResult]=[]
|
|
|
-
|
|
|
+ var returnResult: [LBXScanResult] = []
|
|
|
+
|
|
|
if LBXScanWrapper.isSysIos8Later()
|
|
|
{
|
|
|
//if #available(iOS 8.0, *)
|
|
|
-
|
|
|
- let detector:CIDetector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh])!
|
|
|
-
|
|
|
+
|
|
|
+ let detector: CIDetector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy: CIDetectorAccuracyHigh])!
|
|
|
+
|
|
|
let img = CIImage(cgImage: (image.cgImage)!)
|
|
|
-
|
|
|
- let features:[CIFeature]? = detector.features(in: img, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh])
|
|
|
-
|
|
|
- if( features != nil && (features?.count)! > 0)
|
|
|
+
|
|
|
+ let features: [CIFeature]? = detector.features(in: img, options: [CIDetectorAccuracy: CIDetectorAccuracyHigh])
|
|
|
+
|
|
|
+ if(features != nil && (features?.count)! > 0)
|
|
|
{
|
|
|
let feature = features![0]
|
|
|
-
|
|
|
+
|
|
|
if feature.isKind(of: CIQRCodeFeature.self)
|
|
|
{
|
|
|
- let featureTmp:CIQRCodeFeature = feature as! CIQRCodeFeature
|
|
|
-
|
|
|
+ let featureTmp: CIQRCodeFeature = feature as! CIQRCodeFeature
|
|
|
+
|
|
|
let scanResult = featureTmp.messageString
|
|
|
-
|
|
|
-
|
|
|
- let result = LBXScanResult(str: scanResult, img: image, barCodeType: AVMetadataObject.ObjectType.qr.rawValue,corner: nil)
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
+ let result = LBXScanResult(str: scanResult, img: image, barCodeType: AVMetadataObject.ObjectType.qr.rawValue, corner: nil)
|
|
|
+
|
|
|
returnResult.append(result)
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
return returnResult
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
//MARK: -- - 生成二维码,背景色及二维码颜色设置
|
|
|
- static public func createCode( codeType:String, codeString:String, size:CGSize,qrColor:UIColor,bkColor:UIColor )->UIImage?
|
|
|
+ static public func createCode(codeType: String, codeString: String, size: CGSize, qrColor: UIColor, bkColor: UIColor) -> UIImage?
|
|
|
{
|
|
|
//if #available(iOS 8.0, *)
|
|
|
-
|
|
|
+
|
|
|
let stringData = codeString.data(using: String.Encoding.utf8)
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
//系统自带能生成的码
|
|
|
// CIAztecCodeGenerator
|
|
|
// CICode128BarcodeGenerator
|
|
|
// CIPDF417BarcodeGenerator
|
|
|
// CIQRCodeGenerator
|
|
|
let qrFilter = CIFilter(name: codeType)
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
qrFilter?.setValue(stringData, forKey: "inputMessage")
|
|
|
-
|
|
|
+
|
|
|
qrFilter?.setValue("H", forKey: "inputCorrectionLevel")
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
//上色
|
|
|
- let colorFilter = CIFilter(name: "CIFalseColor", parameters: ["inputImage":qrFilter!.outputImage!,"inputColor0":CIColor(cgColor: qrColor.cgColor),"inputColor1":CIColor(cgColor: bkColor.cgColor)])
|
|
|
-
|
|
|
-
|
|
|
+ let colorFilter = CIFilter(name: "CIFalseColor", parameters: ["inputImage": qrFilter!.outputImage!, "inputColor0": CIColor(cgColor: qrColor.cgColor), "inputColor1": CIColor(cgColor: bkColor.cgColor)])
|
|
|
+
|
|
|
+
|
|
|
let qrImage = colorFilter!.outputImage!;
|
|
|
-
|
|
|
+
|
|
|
//绘制
|
|
|
let cgImage = CIContext().createCGImage(qrImage, from: qrImage.extent)!
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
UIGraphicsBeginImageContext(size);
|
|
|
let context = UIGraphicsGetCurrentContext()!;
|
|
|
context.interpolationQuality = CGInterpolationQuality.none;
|
|
|
@@ -464,16 +525,16 @@ open class LBXScanWrapper: NSObject,AVCaptureMetadataOutputObjectsDelegate {
|
|
|
context.draw(cgImage, in: context.boundingBoxOfClipPath)
|
|
|
let codeImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
|
UIGraphicsEndImageContext();
|
|
|
-
|
|
|
+
|
|
|
return codeImage
|
|
|
-
|
|
|
+
|
|
|
}
|
|
|
-
|
|
|
- static public func createCode128( codeString:String, size:CGSize,qrColor:UIColor,bkColor:UIColor )->UIImage?
|
|
|
+
|
|
|
+ static public func createCode128(codeString: String, size: CGSize, qrColor: UIColor, bkColor: UIColor) -> UIImage?
|
|
|
{
|
|
|
let stringData = codeString.data(using: String.Encoding.utf8)
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
//系统自带能生成的码
|
|
|
// CIAztecCodeGenerator 二维码
|
|
|
// CICode128BarcodeGenerator 条形码
|
|
|
@@ -482,36 +543,36 @@ open class LBXScanWrapper: NSObject,AVCaptureMetadataOutputObjectsDelegate {
|
|
|
let qrFilter = CIFilter(name: "CICode128BarcodeGenerator")
|
|
|
qrFilter?.setDefaults()
|
|
|
qrFilter?.setValue(stringData, forKey: "inputMessage")
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- let outputImage:CIImage? = qrFilter?.outputImage
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ let outputImage: CIImage? = qrFilter?.outputImage
|
|
|
let context = CIContext()
|
|
|
let cgImage = context.createCGImage(outputImage!, from: outputImage!.extent)
|
|
|
-
|
|
|
+
|
|
|
let image = UIImage(cgImage: cgImage!, scale: 1.0, orientation: UIImage.Orientation.up)
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
// Resize without interpolating
|
|
|
- let scaleRate:CGFloat = 20.0
|
|
|
+ let scaleRate: CGFloat = 20.0
|
|
|
let resized = resizeImage(image: image, quality: CGInterpolationQuality.none, rate: scaleRate)
|
|
|
-
|
|
|
+
|
|
|
return resized;
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
//MARK:根据扫描结果,获取图像中得二维码区域图像(如果相机拍摄角度故意很倾斜,获取的图像效果很差)
|
|
|
- static func getConcreteCodeImage(srcCodeImage:UIImage,codeResult:LBXScanResult)->UIImage?
|
|
|
+ static func getConcreteCodeImage(srcCodeImage: UIImage, codeResult: LBXScanResult) -> UIImage?
|
|
|
{
|
|
|
- let rect:CGRect = getConcreteCodeRectFromImage(srcCodeImage: srcCodeImage, codeResult: codeResult)
|
|
|
-
|
|
|
+ let rect: CGRect = getConcreteCodeRectFromImage(srcCodeImage: srcCodeImage, codeResult: codeResult)
|
|
|
+
|
|
|
if rect.isEmpty
|
|
|
{
|
|
|
return nil
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
let img = imageByCroppingWithStyle(srcImg: srcCodeImage, rect: rect)
|
|
|
-
|
|
|
+
|
|
|
if img != nil
|
|
|
{
|
|
|
let imgRotation = imageRotation(image: img!, orientation: UIImage.Orientation.right)
|
|
|
@@ -520,15 +581,15 @@ open class LBXScanWrapper: NSObject,AVCaptureMetadataOutputObjectsDelegate {
|
|
|
return nil
|
|
|
}
|
|
|
//根据二维码的区域截取二维码区域图像
|
|
|
- static public func getConcreteCodeImage(srcCodeImage:UIImage,rect:CGRect)->UIImage?
|
|
|
+ static public func getConcreteCodeImage(srcCodeImage: UIImage, rect: CGRect) -> UIImage?
|
|
|
{
|
|
|
if rect.isEmpty
|
|
|
{
|
|
|
return nil
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
let img = imageByCroppingWithStyle(srcImg: srcCodeImage, rect: rect)
|
|
|
-
|
|
|
+
|
|
|
if img != nil
|
|
|
{
|
|
|
let imgRotation = imageRotation(image: img!, orientation: UIImage.Orientation.right)
|
|
|
@@ -536,51 +597,51 @@ open class LBXScanWrapper: NSObject,AVCaptureMetadataOutputObjectsDelegate {
|
|
|
}
|
|
|
return nil
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
//获取二维码的图像区域
|
|
|
- static public func getConcreteCodeRectFromImage(srcCodeImage:UIImage,codeResult:LBXScanResult)->CGRect
|
|
|
+ static public func getConcreteCodeRectFromImage(srcCodeImage: UIImage, codeResult: LBXScanResult) -> CGRect
|
|
|
{
|
|
|
- if (codeResult.arrayCorner == nil || (codeResult.arrayCorner?.count)! < 4 )
|
|
|
+ if (codeResult.arrayCorner == nil || (codeResult.arrayCorner?.count)! < 4)
|
|
|
{
|
|
|
return CGRect.zero
|
|
|
}
|
|
|
-
|
|
|
- let corner:[[String:Float]] = codeResult.arrayCorner as! [[String:Float]]
|
|
|
-
|
|
|
- let dicTopLeft = corner[0]
|
|
|
- let dicTopRight = corner[1]
|
|
|
+
|
|
|
+ let corner: [[String: Float]] = codeResult.arrayCorner as! [[String: Float]]
|
|
|
+
|
|
|
+ let dicTopLeft = corner[0]
|
|
|
+ let dicTopRight = corner[1]
|
|
|
let dicBottomRight = corner[2]
|
|
|
- let dicBottomLeft = corner[3]
|
|
|
-
|
|
|
- let xLeftTopRatio:Float = dicTopLeft["X"]!
|
|
|
- let yLeftTopRatio:Float = dicTopLeft["Y"]!
|
|
|
-
|
|
|
- let xRightTopRatio:Float = dicTopRight["X"]!
|
|
|
- let yRightTopRatio:Float = dicTopRight["Y"]!
|
|
|
-
|
|
|
- let xBottomRightRatio:Float = dicBottomRight["X"]!
|
|
|
- let yBottomRightRatio:Float = dicBottomRight["Y"]!
|
|
|
-
|
|
|
- let xLeftBottomRatio:Float = dicBottomLeft["X"]!
|
|
|
- let yLeftBottomRatio:Float = dicBottomLeft["Y"]!
|
|
|
-
|
|
|
+ let dicBottomLeft = corner[3]
|
|
|
+
|
|
|
+ let xLeftTopRatio: Float = dicTopLeft["X"]!
|
|
|
+ let yLeftTopRatio: Float = dicTopLeft["Y"]!
|
|
|
+
|
|
|
+ let xRightTopRatio: Float = dicTopRight["X"]!
|
|
|
+ let yRightTopRatio: Float = dicTopRight["Y"]!
|
|
|
+
|
|
|
+ let xBottomRightRatio: Float = dicBottomRight["X"]!
|
|
|
+ let yBottomRightRatio: Float = dicBottomRight["Y"]!
|
|
|
+
|
|
|
+ let xLeftBottomRatio: Float = dicBottomLeft["X"]!
|
|
|
+ let yLeftBottomRatio: Float = dicBottomLeft["Y"]!
|
|
|
+
|
|
|
//由于截图只能矩形,所以截图不规则四边形的最大外围
|
|
|
- let xMinLeft = CGFloat( min(xLeftTopRatio, xLeftBottomRatio) )
|
|
|
- let xMaxRight = CGFloat( max(xRightTopRatio, xBottomRightRatio) )
|
|
|
-
|
|
|
- let yMinTop = CGFloat( min(yLeftTopRatio, yRightTopRatio) )
|
|
|
- let yMaxBottom = CGFloat ( max(yLeftBottomRatio, yBottomRightRatio) )
|
|
|
-
|
|
|
+ let xMinLeft = CGFloat(min(xLeftTopRatio, xLeftBottomRatio))
|
|
|
+ let xMaxRight = CGFloat(max(xRightTopRatio, xBottomRightRatio))
|
|
|
+
|
|
|
+ let yMinTop = CGFloat(min(yLeftTopRatio, yRightTopRatio))
|
|
|
+ let yMaxBottom = CGFloat (max(yLeftBottomRatio, yBottomRightRatio))
|
|
|
+
|
|
|
let imgW = srcCodeImage.size.width
|
|
|
let imgH = srcCodeImage.size.height
|
|
|
-
|
|
|
+
|
|
|
//宽高反过来计算
|
|
|
- let rect = CGRect(x: xMinLeft * imgH, y: yMinTop*imgW, width: (xMaxRight-xMinLeft)*imgH, height: (yMaxBottom-yMinTop)*imgW)
|
|
|
+ let rect = CGRect(x: xMinLeft * imgH, y: yMinTop * imgW, width: (xMaxRight - xMinLeft) * imgH, height: (yMaxBottom - yMinTop) * imgW)
|
|
|
return rect
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
//MARK: ----图像处理
|
|
|
-
|
|
|
+
|
|
|
/**
|
|
|
|
|
|
@brief 图像中间加logo图片
|
|
|
@@ -589,72 +650,72 @@ open class LBXScanWrapper: NSObject,AVCaptureMetadataOutputObjectsDelegate {
|
|
|
@param logoSize logo图像尺寸
|
|
|
@return 加Logo的图像
|
|
|
*/
|
|
|
- static public func addImageLogo(srcImg:UIImage,logoImg:UIImage,logoSize:CGSize )->UIImage
|
|
|
+ static public func addImageLogo(srcImg: UIImage, logoImg: UIImage, logoSize: CGSize) -> UIImage
|
|
|
|
|
|
{
|
|
|
UIGraphicsBeginImageContext(srcImg.size);
|
|
|
srcImg.draw(in: CGRect(x: 0, y: 0, width: srcImg.size.width, height: srcImg.size.height))
|
|
|
- let rect = CGRect(x: srcImg.size.width/2 - logoSize.width/2, y: srcImg.size.height/2-logoSize.height/2, width:logoSize.width, height: logoSize.height);
|
|
|
+ let rect = CGRect(x: srcImg.size.width / 2 - logoSize.width / 2, y: srcImg.size.height / 2 - logoSize.height / 2, width: logoSize.width, height: logoSize.height);
|
|
|
logoImg.draw(in: rect)
|
|
|
let resultingImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
|
UIGraphicsEndImageContext();
|
|
|
return resultingImage!;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
//图像缩放
|
|
|
- static func resizeImage(image:UIImage,quality:CGInterpolationQuality,rate:CGFloat)->UIImage?
|
|
|
+ static func resizeImage(image: UIImage, quality: CGInterpolationQuality, rate: CGFloat) -> UIImage?
|
|
|
{
|
|
|
- var resized:UIImage?;
|
|
|
- let width = image.size.width * rate;
|
|
|
- let height = image.size.height * rate;
|
|
|
-
|
|
|
+ var resized: UIImage?;
|
|
|
+ let width = image.size.width * rate;
|
|
|
+ let height = image.size.height * rate;
|
|
|
+
|
|
|
UIGraphicsBeginImageContext(CGSize(width: width, height: height));
|
|
|
let context = UIGraphicsGetCurrentContext();
|
|
|
context!.interpolationQuality = quality;
|
|
|
image.draw(in: CGRect(x: 0, y: 0, width: width, height: height))
|
|
|
-
|
|
|
+
|
|
|
resized = UIGraphicsGetImageFromCurrentImageContext();
|
|
|
UIGraphicsEndImageContext();
|
|
|
-
|
|
|
+
|
|
|
return resized;
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
//图像裁剪
|
|
|
- static func imageByCroppingWithStyle(srcImg:UIImage,rect:CGRect)->UIImage?
|
|
|
+ static func imageByCroppingWithStyle(srcImg: UIImage, rect: CGRect) -> UIImage?
|
|
|
{
|
|
|
let imageRef = srcImg.cgImage
|
|
|
let imagePartRef = imageRef!.cropping(to: rect)
|
|
|
let cropImage = UIImage(cgImage: imagePartRef!)
|
|
|
-
|
|
|
+
|
|
|
return cropImage
|
|
|
}
|
|
|
//图像旋转
|
|
|
- static func imageRotation(image:UIImage,orientation:UIImage.Orientation)->UIImage
|
|
|
+ static func imageRotation(image: UIImage, orientation: UIImage.Orientation) -> UIImage
|
|
|
{
|
|
|
- var rotate:Double = 0.0;
|
|
|
- var rect:CGRect;
|
|
|
- var translateX:CGFloat = 0.0;
|
|
|
- var translateY:CGFloat = 0.0;
|
|
|
- var scaleX:CGFloat = 1.0;
|
|
|
- var scaleY:CGFloat = 1.0;
|
|
|
-
|
|
|
+ var rotate: Double = 0.0;
|
|
|
+ var rect: CGRect;
|
|
|
+ var translateX: CGFloat = 0.0;
|
|
|
+ var translateY: CGFloat = 0.0;
|
|
|
+ var scaleX: CGFloat = 1.0;
|
|
|
+ var scaleY: CGFloat = 1.0;
|
|
|
+
|
|
|
switch (orientation) {
|
|
|
case UIImage.Orientation.left:
|
|
|
- rotate = .pi/2;
|
|
|
+ rotate = .pi / 2;
|
|
|
rect = CGRect(x: 0, y: 0, width: image.size.height, height: image.size.width);
|
|
|
translateX = 0;
|
|
|
translateY = -rect.size.width;
|
|
|
- scaleY = rect.size.width/rect.size.height;
|
|
|
- scaleX = rect.size.height/rect.size.width;
|
|
|
+ scaleY = rect.size.width / rect.size.height;
|
|
|
+ scaleX = rect.size.height / rect.size.width;
|
|
|
break;
|
|
|
case UIImage.Orientation.right:
|
|
|
- rotate = 3 * .pi/2;
|
|
|
+ rotate = 3 * .pi / 2;
|
|
|
rect = CGRect(x: 0, y: 0, width: image.size.height, height: image.size.width);
|
|
|
translateX = -rect.size.height;
|
|
|
translateY = 0;
|
|
|
- scaleY = rect.size.width/rect.size.height;
|
|
|
- scaleX = rect.size.height/rect.size.width;
|
|
|
+ scaleY = rect.size.width / rect.size.height;
|
|
|
+ scaleX = rect.size.height / rect.size.width;
|
|
|
break;
|
|
|
case UIImage.Orientation.down:
|
|
|
rotate = .pi;
|
|
|
@@ -669,7 +730,7 @@ open class LBXScanWrapper: NSObject,AVCaptureMetadataOutputObjectsDelegate {
|
|
|
translateY = 0;
|
|
|
break;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
UIGraphicsBeginImageContext(rect.size);
|
|
|
let context = UIGraphicsGetCurrentContext()!;
|
|
|
//做CTM变换
|
|
|
@@ -677,15 +738,15 @@ open class LBXScanWrapper: NSObject,AVCaptureMetadataOutputObjectsDelegate {
|
|
|
context.scaleBy(x: 1.0, y: -1.0);
|
|
|
context.rotate(by: CGFloat(rotate));
|
|
|
context.translateBy(x: translateX, y: translateY);
|
|
|
-
|
|
|
+
|
|
|
context.scaleBy(x: scaleX, y: scaleY);
|
|
|
//绘制图片
|
|
|
context.draw(image.cgImage!, in: CGRect(x: 0, y: 0, width: rect.size.width, height: rect.size.height))
|
|
|
let newPic = UIGraphicsGetImageFromCurrentImageContext();
|
|
|
-
|
|
|
+
|
|
|
return newPic!;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
deinit
|
|
|
{
|
|
|
// print("LBXScanWrapper deinit")
|